• .NET Core使用JWT认证、授权


    1、建.NetCore的WebApi项目,安装包IdentityModel,Microsoft.AspNetCore.Authentication.JwtBearer,Microsoft.AspNetCore.Authorization
    2、注册服务和中间件

    using Microsoft.AspNetCore.Authentication.JwtBearer;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.IdentityModel.Tokens;
    using System;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace WebApiJwt.Utils
    {
        public static class AuthorizationSetup
        {
            public static void AddAuthorizationSetup(this IServiceCollection services)
            {
                if (services == null) throw new ArgumentNullException(nameof(services));
                // 策略
                services.AddAuthorization(options =>
                {
                    options.AddPolicy("Admin", policy => policy.RequireRole("Admin", "System"));
                });
    
                //读取配置文件
                var symmetricKeyAsBase64 = ConfigHelper.GetSectionValue("JwtSetting:SecretKey");
                var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
                var signingKey = new SymmetricSecurityKey(keyByteArray);
                var Issuer = ConfigHelper.GetSectionValue("JwtSetting:Issuer");
                var Audience = ConfigHelper.GetSectionValue("JwtSetting:Audience");
    
                // 令牌验证参数
                var tokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,//是否验证签名,不验证的画可以篡改数据,不安全
                    IssuerSigningKey = signingKey,//解密的密钥
                    ValidateIssuer = true,//是否验证发行人,就是验证载荷中的Iss是否对应ValidIssuer参数
                    ValidIssuer = Issuer,//发行人
                    ValidateAudience = true,//是否验证订阅人,就是验证载荷中的Aud是否对应ValidAudience参数
                    ValidAudience = Audience,//订阅人
                    ValidateLifetime = true,//是否验证过期时间,过期了就拒绝访问
                    ClockSkew = TimeSpan.Zero,//缓冲过期时间,真正过期时间=配置过期时间+缓冲过期时间,默认5分钟
                    RequireExpirationTime = true,//token需要设置过期时间
                };
    
                // 开启Bearer认证,添加JwtBearer服务
                services.AddAuthentication(o =>
                {
                    o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                })
                .AddJwtBearer(o =>
                {
                    o.TokenValidationParameters = tokenValidationParameters;
                    o.Events = new JwtBearerEvents
                    {
                        OnAuthenticationFailed = context =>
                        {
                            // 如果过期,则把<是否过期>添加到,返回头信息中
                            if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                            {
                                context.Response.Headers.Add("Token-Expired", "true");
                            }
                            return Task.CompletedTask;
                        }
                    };
                });
            }
        }
    }
    

     Startup.cs
    注册服务:services.AddAuthorizationSetup();
    添加中间件:app.UseAuthentication(); app.UseAuthorization();
    3、生成Token

    using Microsoft.IdentityModel.Tokens;
    using System;
    using System.Collections.Generic;
    using System.IdentityModel.Tokens.Jwt;
    using System.Linq;
    using System.Security.Claims;
    using System.Text;
    using WebApiJwt.Models;
    
    namespace WebApiJwt.Utils
    {
        public class JwtHelper
        {
            /// <summary>
            /// 颁发JWT字符串
            /// </summary>
            /// <param name="tokenModel"></param>
            /// <returns></returns>
            public static object IssueJwt(TokenModel tokenModel)
            {
                DateTime authTime = DateTime.UtcNow;
                string iss = ConfigHelper.GetSectionValue("JwtSetting:Issuer");//颁发者
                string aud = ConfigHelper.GetSectionValue("JwtSetting:Audience");//可以给哪些客户端使用
                string secret = ConfigHelper.GetSectionValue("JwtSetting:SecretKey");//加密的Key
                //token有效期 分钟
                DateTime expiresAt = authTime.AddMinutes(Convert.ToDouble(ConfigHelper.GetSectionValue("JwtSetting:ExpireMinutes")));
    
                //设置Claim
                var claims = new List<Claim>
                {
                    //claim默认配置
                    new Claim(JwtRegisteredClaimNames.Jti, tokenModel.UserId.ToString()),
                    new Claim(JwtRegisteredClaimNames.Iat, $"{new DateTimeOffset(authTime).ToUnixTimeSeconds()}"),
                    new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(authTime).ToUnixTimeSeconds()}") ,
    
                    //过期时间,JWT有缓冲过期时间,所以过期时间到了会延迟一会儿再过期,影响不大。
                    new Claim(JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(expiresAt).ToUnixTimeSeconds()}"),
                    new Claim(ClaimTypes.Expiration, expiresAt.ToString()),
    
                    new Claim(JwtRegisteredClaimNames.Iss,iss),//颁发者
                    new Claim(JwtRegisteredClaimNames.Aud,aud),//可以给哪些客户端使用
    
                    new Claim(ClaimTypes.Name, tokenModel.UserName),
                    new Claim(ClaimTypes.Email, tokenModel.Email)
                };
                //设置Claim角色
                claims.AddRange(tokenModel.Role.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));
    
                //秘钥 (SymmetricSecurityKey 对安全性的要求,密钥的长度太短会报出异常)
                var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
                var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
                var jwtSecurityToken = new JwtSecurityToken(issuer: iss, claims: claims, signingCredentials: creds);
                var jwtHandler = new JwtSecurityTokenHandler();
                var encodedJwt = jwtHandler.WriteToken(jwtSecurityToken);
                //存储 Token 信息
                var jwt = new
                {
                    UserId = tokenModel.UserId,
                    Token = encodedJwt,
                    Auths = new DateTimeOffset(authTime).ToUnixTimeSeconds(),
                    Expires = new DateTimeOffset(expiresAt).ToUnixTimeSeconds(),
                    Success = true
                };
                return jwt;
            }
    
            /// <summary>
            /// 解析
            /// </summary>
            /// <param name="jwtStr"></param>
            /// <returns></returns>
            public static TokenModel SerializeJwt(string jwtStr)
            {
                var jwtHandler = new JwtSecurityTokenHandler();
                if (!jwtHandler.CanReadToken(jwtStr)) { return null; }
                string iss = ConfigHelper.GetSectionValue("JwtSetting:Issuer");
                JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);
                if (jwtToken.Issuer != iss)
                {
                    return null;//不正确
                }
                if (jwtToken.ValidTo < DateTime.UtcNow)
                {
                    return null;//过期
                }
                object role, userName, email;
                try
                {
                    jwtToken.Payload.TryGetValue(ClaimTypes.Role, out role);
                    jwtToken.Payload.TryGetValue(ClaimTypes.Name, out userName);
                    jwtToken.Payload.TryGetValue(ClaimTypes.Email, out email);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }
                var tm = new TokenModel
                {
                    UserId = jwtToken.Id.ToString(),
                    Role = role != null ? role.ToString() : "",
                    UserName = userName != null ? userName.ToString() : "",
                    Email = email != null ? email.ToString() : ""
                };
                return tm;
            }
        }
    }
    

     配置

    "JwtSetting": {
        "Issuer": "jwtIssuer", //颁发者
        "Audience": "jwtAudience", //可以给哪些客户端使用
        "SecretKey": "chuangqianmingyueguang", //加密的Key
        "ExpireMinutes": "3" //token有效期3分钟
    }
    

     辅助

    using Microsoft.Extensions.Configuration;
    using System;
    
    namespace WebApiJwt.Utils
    {
        public class ConfigHelper
        {
            public readonly static IConfiguration configuration;
            static ConfigHelper()
            {
                configuration = new ConfigurationBuilder()
                .SetBasePath(Environment.CurrentDirectory)
                .AddJsonFile("appsettings.json", true, true)
                .AddInMemoryCollection()
                .Build();
            }
            public static string GetSectionValue(string key)
            {
                return configuration[key];
            }
            public static string connectionString
            {
                get { return configuration["ConnectionStrings:Default"]; }
            }
        }
    }
    

     4、ApiController

    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Newtonsoft.Json;
    using WebApiJwt.Models;
    using WebApiJwt.Utils;
    
    namespace WebApiJwt.Controllers
    {
        [Route("api/[controller]/[action]")]
        [ApiController]
        public class AuthorizeController : ControllerBase
        {
            /// <summary>
            /// 生成令牌
            /// </summary>
            /// <returns></returns>
            [HttpGet]
            public string GenToken()
            {
                TokenModel tokenModel = new TokenModel { UserId = "1001", Role = "Admin", Email = "908085411@qq.com", UserName = "邢帅杰" };
                string jwtToken = JsonConvert.SerializeObject(JwtHelper.IssueJwt(tokenModel));
                return jwtToken;
            }
    
            /// <summary>
            /// 需要Admin权限
            /// </summary>
            /// <returns></returns>
            [HttpGet]
            [Authorize(Roles = "Admin")]
            //[Authorize(Policy = "Admin")]//使用策略来映射多个角色
            public IActionResult Admin()
            {
                return Ok("admin........");
            }
    
            /// <summary>
            /// 解析Token
            /// </summary>
            /// <returns></returns>
            [HttpGet]
            [Authorize]
            public IActionResult AnalysisToken()
            {
                var tokenHeader = HttpContext.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
                var user = JwtHelper.SerializeJwt(tokenHeader);
                return Ok(user);
            }
        }
    }
    

    5、 生成:https://localhost:44393/api/Authorize/GenToken,解析:https://localhost:44393/api/Authorize/AnalysisToken,在header中添加 Authorization:Bearer token
    参考:

    https://www.cnblogs.com/danvic712/p/10331976.html
    https://blog.csdn.net/weixin_42045719/article/details/91973878
    http://cn.voidcc.com/question/p-vckjdtzx-hv.html
    https://www.cnblogs.com/danvic712/p/10331976.html
    https://blog.csdn.net/baidu_35726140/article/details/84867520
    https://www.cnblogs.com/xwc1996/p/14058115.html

  • 相关阅读:
    .NET开发人员如何开始使用ML.NET
    微软开源 Try .NET
    在kubernetes 集群内访问k8s API服务
    微软发布ML.NET 1.0
    现代“十二要素应用”与 Kubernetes
    .NET和Docker ,比翼双飞
    .NET Core 时代已经到了,你准备好了吗
    一份.NET 容器化的调查小结
    容器化时代我们应当选择Kubernetes
    机器学习 ML.NET 发布 1.0 RC
  • 原文地址:https://www.cnblogs.com/xsj1989/p/15357741.html
Copyright © 2020-2023  润新知