使用WebApi加Token验证(JWT)

今天来做一个webapi的安全管控验证的案例

我们知道webapi密匙验证也有不少,比如OAuth2.0.。。。我们今天用JWT这种方式来做一个账号密码换取Token的案例

基本流程是 输入账号密码--->后台比对==true -->return Token else 未登录

                                             所有控制器必须继承自基础类,基础类我们用权限特性控制

 

老规矩,需要用到的工具

VS2019 NetCore3.1,Postman 调试用

 

我们看下主要结构如下

使用WebApi加Token验证(JWT)

记得引用包

使用WebApi加Token验证(JWT)

 

 

 

我们一个个类来看

 1  /// <summary>
 2     /// 基础控制器类
 3     /// </summary>
 4     [Route("api/[controller]/[action]")]
 5     [ApiController]
 6     [ActionFilterAttribute]
 7     public class BaseController : ControllerBase
 8     {
 9         /// <summary>
10         /// 获取Token的方法
11         /// </summary>
12         /// <param name="userId"></param>
13         /// <param name="token1"></param>
14         /// <returns></returns>
15         [NonAction]
16         protected string GetJwtToken(string userId,string token1)
17         {
18             var jwtHandle = new JwtSecurityTokenHandler { };
19 
20             var token = jwtHandle.CreateJwtSecurityToken(
21                 "test",
22                 "test",
23                 new ClaimsIdentity(new Claim[]{
24                     new Claim("name2","tt2"),
25                     new Claim("role2","user"),
26                     new Claim("token",token1),
27                     new Claim("c_uid",userId),
28                 }),
29                 System.DateTime.Now,
30                 //设置过期
31                 System.DateTime.Now.AddMilliseconds(3000.00),
32                 System.DateTime.Now,
33                 new SigningCredentials(
34                     new SymmetricSecurityKey(System.
35                     Text.
36                     Encoding.
37                     ASCII.GetBytes("6mSzczZX3KgZ3HOX")),
38                     SecurityAlgorithms.HmacSha256)
39             );
40 
41             return jwtHandle.WriteToken(token);
42         }
43     }

 

 这个基础控制类我们这里就写一个方法吧,就是生成Token,当然是在匹配用户名密码正确之后调用

接下来是这个权限特性 这里都做了注释,不再一一解释

    /// 权限过滤特性
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
    public class ActionFilterAttribute : Attribute, IAsyncActionFilter, IAsyncAlwaysRunResultFilter
    {
        /// <summary>
        /// 忽略token的方法
        /// </summary>
        public static readonly string[] IgnoreToken = {"Login"};


        /// <summary>
        /// 校验过滤器
        /// </summary>
        /// <param name="context"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            //获取用户声明中的Token
            var UserToken = context.HttpContext.User.FindFirstValue("token");
            //执行的动作
            var action = context.RouteData.Values["Action"].ToString();

            if (IgnoreToken.Count(s => s == action) == 0)
            {
                if (UserToken is null)
                {
                    context.Result = new JsonResult("用户未登录!");
                    return;
                }
                //现实中获取数据库对比用户唯一识别token,非加密的那个
                if (!UserToken.Equals("123456"))
                {
                    context.Result = new JsonResult("Token失效!");
                    return;
                }
            }
            
            //抛转下一个中间件
            var resultContext = await next();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
        {
            var resultContext = await next();
        }
}

然后我们需要看下StartUp类中我们需要使用这个中间件才可以正常使用

public void ConfigureServices(IServiceCollection services)
        {
            //注册JWT
            services.AddAuthentication()
                    .AddIdentityServerJwt();
            services.Configure<JwtBearerOptions>(
                IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
                options =>
                {
                    var onTokenValidated = options.Events.OnTokenValidated;
                    var onMessageReceived = options.Events.OnMessageReceived;

                    options.Events.OnTokenValidated = async context =>
                    {
                        await onTokenValidated(context);
                    };
                    options.Events.OnMessageReceived = async context =>
                    {
                        /*
                        https://www.cnblogs.com/liuww/p/12177272.html
                        https://www.cnblogs.com/RainingNight/p/jwtbearer-authentication-in-asp-net-core.html
                        https://www.cnblogs.com/jesse2013/p/integrate-with-lagacy-auth.html
                        https://www.cnblogs.com/nsky/p/10312101.html
                        */
                        // await onMessageReceived(context);
                        var token = context.Request.Headers["token"];
                        if (string.IsNullOrEmpty(token))
                        {
                            token = context.Request.Query["token"];
                        }
                        context.Token = token.FirstOrDefault();
                        // return await System.Threading.Tasks.Task.CompletedTask;
                    };
                    //Token认证注册
                    options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
                    {
                        ValidIssuer = "test",
                        ValidAudience = "test",
                        IssuerSigningKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(System.Text.Encoding.ASCII.GetBytes("6mSzczZX3KgZ3HOX"))
                    };
                });

            services.AddControllers();
        }

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            app.UseAuthentication();
            //app.UseAuthorization();
           

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

 

上面都写好之后

我们看下用户类这里只做两个东西,一个登录,一个获取数据,注意登录是公开的,获取用户信息是私密的

使用WebApi加Token验证(JWT)

 

我们运行一下调试看看
打开Postman发现直接调用获取用户信息是被拒绝的

使用WebApi加Token验证(JWT)

 


 好了,我们再尝试通过用户名密码换取Token

使用WebApi加Token验证(JWT)

 

 

我们发现我们成功换取到了token,然后我们再用Token去请求刚才提示拒绝的接口

使用WebApi加Token验证(JWT)

 

 

我们看到已经非常友好的接受了我们的请求。当然这是一个最基本的用户名密码换取Token的验证,如果是前后端分离,我们还要有秘钥等等验证,但是小程序里面的话,那么我们可以通过这种验证实现移动端网页端的调用。

 

 

使用WebApi加Token验证(JWT)

上一篇:C#语法基础08_foreach


下一篇:Windows下配置hadoop进行本地开发