对与asp.net core web api验证,多种方式,本例子的方式采用的是李争的《微软开源跨平台移动开发实践》中的token验证方式。

Asp.net core web api项目代码:

首先定义三个Token相关的类,一个Token实体类,一个TokenProvider类,一个TokenProviderOptions类

代码如下:

/// <summary>
/// Token实体
/// </summary>
public class TokenEntity
{
    /// <summary>
    /// token字符串
    /// </summary>
    public string access_token { get; set; }
    /// <summary>
    /// 过期时差
    /// </summary>
    public int expires_in { get; set; }
}
/// <summary>
/// token提供属性
/// </summary>
public class TokenProviderOptions
{
    /// <summary>
    /// 发行人
    /// </summary>
    public string Issuer { get; set; }
    /// <summary>
    /// 订阅者
    /// </summary>
    public string Audience { get; set; }
    /// <summary>
    /// 过期时间间隔
    /// </summary>
    public TimeSpan Expiration { get; set; } = TimeSpan.FromSeconds(30);
    /// <summary>
    /// 签名证书
    /// </summary>
    public SigningCredentials SigningCredentials { get; set; }
}
 
/// <summary>
 /// Token提供类
 /// </summary>
 public class TokenProvider
 {
     readonly TokenProviderOptions _options;
     public TokenProvider(TokenProviderOptions options)
     {
         _options = options;
     }
     /// <summary>
     /// 生成令牌
     /// </summary>
     /// <param name="context">http上下文</param>
     /// <param name="username">用户名</param>
     /// <param name="password">密码</param>
     /// <param name="role">角色</param>
     /// <returns></returns>
     public async Task<TokenEntity> GenerateToken(HttpContext context, string username, string password, string role)
     {
         var identity = await GetIdentity(username);
         if (identity == null)
         {
             return null;
         }
         var now = DateTime.UtcNow;
         //声明
         var claims = new Claim[]
         {
             new Claim(JwtRegisteredClaimNames.Sub,username),
             new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString()),
             new Claim(JwtRegisteredClaimNames.Iat,ToUnixEpochDate(now).ToString(),ClaimValueTypes.Integer64),
             new Claim(ClaimTypes.Role,role),
             new Claim(ClaimTypes.Name,username)
         };
         //Jwt安全令牌
         var jwt = new JwtSecurityToken(
             issuer: _options.Issuer,
             audience: _options.Audience,
             claims: claims,
             notBefore: now,
             expires: now.Add(_options.Expiration),
             signingCredentials: _options.SigningCredentials);
         //生成令牌字符串
         var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
         var response = new TokenEntity
         {
             access_token = encodedJwt,
             expires_in = (int)_options.Expiration.TotalSeconds
         };
         return response;
     }
 
     private static long ToUnixEpochDate(DateTime date)
     {
         return (long)Math.Round((date.ToUniversalTime() - new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero)).TotalSeconds);
     }
     /// <summary>
     /// 查看令牌是否存在
     /// </summary>
     /// <param name="username">用户名</param>
     /// <returns></returns>
     private Task<ClaimsIdentity> GetIdentity(string username)
     {
         return Task.FromResult(
             new ClaimsIdentity(new System.Security.Principal.GenericIdentity(username, "token"),
             new Claim[] {
                 new Claim(ClaimTypes.Name, username)
             }));
     }
 }

Startup.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using System.Text;
  
namespace WebApiAuthentication
{
    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                .AddEnvironmentVariables();
            Configuration = builder.Build();
        }
 
        public IConfigurationRoot Configuration { get; }  
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
        }
 
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();
            //自定义密钥
            var secretKey = "ThisIsASecretKeyForAspNetCoreAPIToken";
            //生成SymmetricSecurityKey密钥
            var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));
            //令牌验证参数
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = signingKey,
                ValidateIssuer = true,
                ValidIssuer = "issuer",
                ValidateAudience = true,
                ValidAudience = "audience",
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero
 
            };
            //使用Jwt持票人身份验证
            app.UseJwtBearerAuthentication(new JwtBearerOptions
            {
                AutomaticAuthenticate = true,
                AutomaticChallenge = true,
                TokenValidationParameters = tokenValidationParameters
            });
 
            app.UseMvc();
        }
    }
}

AccountController.cs

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using Microsoft.Extensions.Options;
 
namespace WebApiAuthentication.Controllers
{   
    [Route("api/v1/[controller]/[action]")]
    public class AccountController : Controller
    {      
        [HttpPost]
        [Authorize(Roles ="admin")]
        public JsonResult ABC()
        {
            return new JsonResult(new
            {
                Name = "张三",
                Age = 12,
                Sex = true,
                User=User.Identity.Name,
               
 
            }, new Newtonsoft.Json.JsonSerializerSettings());
        }
        [AllowAnonymous]
        public IActionResult Login()
        {
            return View();
        }
        /// <summary>
        /// 登录action
        /// </summary>
        /// <param name="username">用户名</param>
        /// <param name="password">密码</param>
        /// <param name="role">角色</param>
        /// <returns></returns>
        [HttpPost]
        [AllowAnonymous]
        public async Task<IActionResult> Login(string username, string password,string role)
        {
            var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("ThisIsASecretKeyForAspNetCoreAPIToken"));
            var options = new TokenProviderOptions
            {
                Audience = "audience",
                Issuer = "issuer",
                SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256)
            };
            var tpm = new TokenProvider(options);
            var token = await tpm.GenerateToken(HttpContext, username, password,role);
            if (null != token)
            {
                return new JsonResult(token);
            }
            else
            {
                return NotFound();
            }
        }
    }
}

客户端代代码是用RestSharp来实现,代码如下:

using RestSharp;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace WebApiAuthenticationClientTest
{
    class Program
    {
        static void Main(string[] args)
        {         
            dynamic token = null;
            while (true)
            {
                Console.WriteLine("1、登录 2、查询数据 ");
                var mark = Console.ReadLine();
                var  stopwatch = new Stopwatch();
                stopwatch.Start();
                switch (mark)
                {
                    case "1":
                        var loginClient = new RestClient("http://localhost:5000");
                        var loginRequest = new RestRequest("/api/v1/account/login", Method.POST);
                        loginRequest.AddParameter("username", "dsfsdf");
                        loginRequest.AddParameter("password", "111111");
                        //或用用户名密码查询对应角色
                        loginRequest.AddParameter("role", "admin");
                        IRestResponse loginResponse = loginClient.Execute(loginRequest);
                        var loginContent = loginResponse.Content;
                        Console.WriteLine(loginContent);
                        token = Newtonsoft.Json.JsonConvert.DeserializeObject(loginContent);
                        break;
                    case "2":
                        var client = new RestClient("http://localhost:5000");
                        //这里要在获取的令牌字符串前加Bearer
                        string tk = "Bearer " + Convert.ToString(token?.access_token);
                        client.AddDefaultHeader("Authorization", tk);
                        var request = new RestRequest("/api/v1/account/abc", Method.POST);
                        IRestResponse response = client.Execute(request);
                        var content = response.Content;              
                        Console.WriteLine($"状态:{response.StatusCode}  返回结果:{content}");
                        break;            
                }    
                stopwatch.Stop();
                TimeSpan timespan = stopwatch.Elapsed;
                Console.WriteLine($"间隔时间:{timespan.TotalSeconds}");
            }
        }
    }
}


运行服务端,再运行客户端,测试如下,没有登录前的查询返回状态是Unauthorized,登录后再查询的状态是OK

wKioL1iIgSyhqsLrAAJGcsxRpZk914.png-wh_50