zoukankan      html  css  js  c++  java
  • .net core 2.0 jwt身份认证系统

    经历了很久,.net core 2.0 终于发布了!

    之前一直用的core 1.1,升级了2.0后发现认证的机制(Auth)发生了比较大的变化,在1.1中认证配置是在Configure中完成,而在2.0中,认证配置则是在ConfigureServices中完成,刚好对调了一下。

    话不多说,直接看代码

    1.ConfigureServices中的认证配置

                var audienceConfig = Configuration.GetSection("Audience");
                var symmetricKeyAsBase64 = audienceConfig["Secret"];
                var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
                var signingKey = new SymmetricSecurityKey(keyByteArray);
    
                var tokenValidationParameters = new TokenValidationParameters
                {
    
                    // The signing key must match!
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = signingKey,
    
                    // Validate the JWT Issuer (iss) claim
                    ValidateIssuer = true,
                    ValidIssuer = audienceConfig["Issuer"],
    
                    // Validate the JWT Audience (aud) claim
                    ValidateAudience = true,
                    ValidAudience = audienceConfig["Audience"],
    
                    // Validate the token expiry
                    ValidateLifetime = true,
    
                    ClockSkew = TimeSpan.Zero
                };
                services.AddAuthentication(options =>
                {
                    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                })
                .AddJwtBearer(o =>
                {
                    //不使用https
                    //o.RequireHttpsMetadata = false;
                    o.TokenValidationParameters = tokenValidationParameters;
                });

    贴上appsettings.json的内容

    "Audience": {
        "Secret": "Y2F0Y2yhciUyMHdvbmclMFWfsaZlJTIwLm5ldA==",
        "Issuer": "test",
        "Audience": "test"
      }

    2. Configure中使用认证,这里我扩展了UseAuthentication的方法。

    (1)先定义一个TokenProviderOptions类

    public class TokenProviderOptions
        {
            /// <summary>
            /// 请求路径
            /// </summary>
            public string Path { get; set; } = "/Api/Token";
    
            public string Issuer { get; set; }
    
            public string Audience { get; set; }
            /// <summary>
            /// 过期时间
            /// </summary>
            public TimeSpan Expiration { get; set; } = TimeSpan.FromMinutes(5000);
    
            public SigningCredentials SigningCredentials { get; set; }
        }

    (2)定义一个TokenProviderExtensions类扩展UseAuthentication方法

     public static class TokenProviderExtensions
        {
            public static IApplicationBuilder UseAuthentication(this IApplicationBuilder app, TokenProviderOptions options)
            {
                if (app == null)
                {
                    throw new ArgumentNullException(nameof(app));
                }
                return app.UseMiddleware<TokenProviderMiddleware>(Options.Create(options));
            }
        }

    至于为什么UseAuthentication为什么长这样的,可以看https://github.com/aspnet/Security/blob/99aa3bd35dd5fbe46a93eef8a2c8ab1f9fe8d05b/src/Microsoft.AspNetCore.Authentication/AuthAppBuilderExtensions.cs源代码

    (3)写了TokenProviderMiddleware类来代替AuthenticationMiddleware

     public class TokenProviderMiddleware
        {
            private readonly RequestDelegate _next;
            private readonly TokenProviderOptions _options;
            private readonly IUserService _service;
            public TokenProviderMiddleware(
                RequestDelegate next,
                IOptions<TokenProviderOptions> options, IAuthenticationSchemeProvider schemes)
            {
                _next = next;
                _options = options.Value;
                Schemes = schemes;
            }
            public IAuthenticationSchemeProvider Schemes { get; set; }
    
            /// <summary>
            /// invoke the middleware
            /// </summary>
            /// <param name="context"></param>
            /// <returns></returns>
            public async Task Invoke(HttpContext context,IUserServcice service)
            {
           _sercice=service;
    // context.Features.Set<IAuthenticationFeature>(new AuthenticationFeature { OriginalPath = context.Request.Path, OriginalPathBase = context.Request.PathBase }); //获取默认Scheme(或者AuthorizeAttribute指定的Scheme)的AuthenticationHandler var handlers = context.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>(); foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync()) { var handler = await handlers.GetHandlerAsync(context, scheme.Name) as IAuthenticationRequestHandler; if (handler != null && await handler.HandleRequestAsync()) { return; } } var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync(); if (defaultAuthenticate != null) { var result = await context.AuthenticateAsync(defaultAuthenticate.Name); if (result?.Principal != null) { context.User = result.Principal; } } // if (!context.Request.Path.Equals(_options.Path, StringComparison.Ordinal)) { await _next(context); return; } // Request must be POST with Content-Type: application/x-www-form-urlencoded if (!context.Request.Method.Equals("POST") || !context.Request.HasFormContentType) { await ReturnBadRequest(context); return; } await GenerateAuthorizedResult(context); } /// <summary> /// 验证结果并得到token /// </summary> /// <param name="context"></param> /// <returns></returns> private async Task GenerateAuthorizedResult(HttpContext context) { var username = context.Request.Form["username"]; var password = context.Request.Form["password"]; var identity = await GetIdentity(username, password); if (identity == null) { await ReturnBadRequest(context); return; } // Serialize and return the response context.Response.ContentType = "application/json"; await context.Response.WriteAsync(GetJwt(username)); } /// <summary> /// 验证用户 /// </summary> /// <param name="username"></param> /// <param name="password"></param> /// <returns></returns> private Task<ClaimsIdentity> GetIdentity(string username, string password) { var isValidated = _service.Auth(username,password); if (isValidated) { return Task.FromResult(new ClaimsIdentity(new System.Security.Principal.GenericIdentity(username, "Token"), new Claim[] { })); } return Task.FromResult<ClaimsIdentity>(null); } /// <summary> /// return the bad request (200) /// </summary> /// <param name="context"></param> /// <returns></returns> private async Task ReturnBadRequest(HttpContext context) { context.Response.StatusCode = 200; await context.Response.WriteAsync(JsonConvert.SerializeObject(new { Status = false, Message = "认证失败" })); } /// <summary> /// get the jwt /// </summary> /// <param name="username"></param> /// <returns></returns> private string GetJwt(string username) { var now = DateTime.UtcNow; var claims = new Claim[] { new Claim(JwtRegisteredClaimNames.Sub, username), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), new Claim(JwtRegisteredClaimNames.Iat, now.ToUniversalTime().ToString(), ClaimValueTypes.Integer64), //用户名 new Claim(ClaimTypes.Name,username), //角色 new Claim(ClaimTypes.Role,"a") }; 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 { Status=true, access_token = encodedJwt, expires_in = (int)_options.Expiration.TotalSeconds, token_type = "Bearer" }; return JsonConvert.SerializeObject(response, new JsonSerializerSettings { Formatting = Formatting.Indented }); } }

    (4)最后Configure中使用认证

     var audienceConfig = Configuration.GetSection("Audience");
                var symmetricKeyAsBase64 = audienceConfig["Secret"];
                var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
                var signingKey = new SymmetricSecurityKey(keyByteArray);
                var SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
                app.UseAuthentication(new TokenProviderOptions
                {
                    Audience = audienceConfig["Audience"],
                    Issuer = audienceConfig["Issuer"],
                    SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256)
                });

    3.最后的测试

  • 相关阅读:
    【转载】 卷积神经网络(Convolutional Neural Network,CNN)
    【转载】 深度学习之卷积神经网络(CNN)详解与代码实现(一)
    【边缘计算】 Edge Computing: Vision and Challenges
    【转载】 一种替代性的基于模拟的搜索方法,即策略梯度搜索
    【转载】 共享相关任务表征,一文读懂深度神经网络多任务学习
    【转载】 另一种(深度)学习:自我监督学习会是下一个重点导向吗?
    【转载】 谷歌做了个机器人,扔东西比人准多了 | 极客酷玩
    【节选 转载】 当前的迁移学习算法进行分类
    【转载】 第四范式首席科学家杨强:AlphaGo的弱点及迁移学习的应对(附视频)
    Flash打开新窗口 被浏览器拦截问题 navigateToURL被拦截 真正试验结果
  • 原文地址:https://www.cnblogs.com/hzzxq/p/7373287.html
Copyright © 2011-2022 走看看