.netcore实现jwt身份验证

前言

http协议本身是一种无状态的协议。所以客户端的每次请求,服务端是不清楚其身份的,需要客户端每次都要将身份信息传入,服务进行验证,才能达到安全验证的目的。

传统的Web用户验证:
1、客户端传入用户名和密码---2、后端验证成功后保存session信息,并将session信息返回给客户端--3、客户端保存session信息到cookie中---
4、客户端再请求需要的资源时,将cookie中的session信息传给服务端--5、服务端验证信息是否正确,正确则进行相应的操作,不正确则返回登录页面或者提示错误。

当然传统的session-cookie方式是可以达到用户身份验证的目的,但是在分布式的场景下就不好使了。因为session是存在当时对应的服务器中的,当我们部署多台服务器,并采用了负载均衡时,session不共享时,只能在其验证的服务器上才能通过,而无法达到多台服务器协同负载工作。(当然也可以通过将session信息存于数据库或者是分布式缓存中,每次需要验证时从数据库或者缓存中获取做验证,但是这样就多了一重数据库操作,或者是缓存出问题时无法验证)。

Token验证模式:
1、客户端使用用户名密码来请求服务器--2、服务器验证用户信息,成功则返回客户端一个token信息--3、客户端留存token信息,在每次请求时将token一并传给服务端--4、服务端验证token,正确则返回数据。

Jwt(Json web token), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的。它主要由3部分数据组成:头部(header),载荷(payload),签名(signature)。其实它就是token,服务端验证成功后按照算法组成jwt,返回给客户端;客户端请求服务端附带jwt,服务端验证jwt正确性,正确则返回对应的数据

.netcore实现jwt身份验证(同时集成swagger)

 1、在appsettings.json文件中配置(注意这些配置信息的安全性,特别是secretkey。secretkey长度一般要求16位或以上)

 "JwtSettings": {
    "Issuer": "john_yong",
    "Audience": "user",
    "SecretKey": "123456789123456789"
  },

 

2、在startup.cs的ConfigureServices(IServiceCollection services)方法中配置

     services.Configure<JwtSetting>(Configuration.GetSection("JwtSettings"));
     JwtSetting setting = new JwtSetting();
     Configuration.Bind("JwtSettings", setting); 

      #region swagger
            services.AddSwaggerGen(p =>
            {
                p.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
                {
                    Version = "v1",
                    Title = "SimpleTest API 接口文档",
                    //Contact = new OpenApiContact
                    //{
                    //    Name = "john_yong",
                    //    Email = "gxunet@163.com",
                    //    Url = new Uri("http://xxxx.com"),
                    //},
                });

                //p.OperationFilter<HttpHeaderOperation>(); // 添加httpHeader参数
                #region 启用swagger验证功能
                p.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
                {
                    Description = "在下框中输入请求头中需要添加Jwt授权Token:Bearer Token",
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.ApiKey,
                    BearerFormat = "JWT",
                    Scheme = "Bearer"
                });
                p.AddSecurityRequirement(new OpenApiSecurityRequirement
                        {
                            {
                                new OpenApiSecurityScheme
                                {
                                    Reference = new OpenApiReference {
                                        Type = ReferenceType.SecurityScheme,
                                        Id = "Bearer"
                                    }
                                },
                                new string[] { }
                            }
                        });
                #endregion
                // 为 Swagger JSON and UI设置xml文档注释路径
                var xmlPath = Path.Combine(AppContext.BaseDirectory, "SimpleTestApplication.xml");
 
                p.IncludeXmlComments(xmlPath );
            });

            #endregion
            #region 添加验证服务 
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(p =>
                {
                    p.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = true,
                        ValidateAudience = true,
                        ValidateLifetime = true,
                        ClockSkew = TimeSpan.FromSeconds(30),
                        ValidateIssuerSigningKey = true,
                        ValidAudience = setting.Audience,
                        ValidIssuer = setting.Issuer,
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(setting.SecretKey))
                    };
                });
              #endregion

 

在 Configure(IApplicationBuilder app, IWebHostEnvironment env)方法中配置

   //启用授权
            app.UseAuthentication();

            app.UseAuthorization();


JwtSetting.cs

 /// <summary>
    /// 
    /// </summary>
    public class JwtSetting
    {
        /// <summary>
        /// 证书颁发者
        /// </summary>
        public string Issuer { get; set; }

        /// <summary>
        ///  角色
        /// </summary>
        public string Audience { get; set; }

        /// <summary>
        /// 加密字符串
        /// </summary>
        public string SecretKey { get; set; }
    }

 

3、创建AuthController提供api验证获取jwt
    [ApiController]
    [Route("[controller]")]
    public class AuthController : Controller
    {
        private JwtSetting _jwtSettings;
        public AuthController(IOptions<JwtSetting> jwtSetting)
        {
            _jwtSettings = jwtSetting.Value;
        }
        /// <summary>
        /// 获取token 
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="pwd"></param>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpGet("getToken")]
        public ResponseFormatDto<TokenInfo> GetToken(string userName, string pwd)
        {
            double expiredMinute = 30;   //过期时间30分钟
            DateTime expiredTime = DateTime.Now.AddMinutes(expiredMinute);
            //TODO验证用户
            if (userName == "admin" && pwd == "1234560")
            {
                var claims = new[]
                {
                    new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,
                    new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(expiredTime).ToUnixTimeSeconds()}"),
                    new Claim(ClaimTypes.Name, userName)
                };
                var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.SecretKey));
                var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
                var jwtSecurityToken = new JwtSecurityToken(
                    issuer: _jwtSettings.Issuer,
                    audience: _jwtSettings.Audience,
                    claims: claims,
                    expires: expiredTime,
                    signingCredentials: creds);
                string token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
                TokenInfo tokenInfo = new TokenInfo()
                {
                    Token = token,
                    Expired = expiredTime
                };
                return HelperTool.GetResponse(tokenInfo);

            }
            else
            {
                return HelperTool.GetResponse<TokenInfo>(null, Status.Fail, "username or password is incorrect.");
            }
        }
    }

 

TokenInfo.cs

    /// <summary>
    /// token information
    /// </summary>
    public class TokenInfo
    {
        /// <summary>
        /// token
        /// </summary>
        public string Token { get; set; }
        /// <summary>
        /// 过期时间
        /// </summary>
        public DateTime Expired { get; set; }

    }

 

HelperTool.cs是简单通用的构造统一的返回实体ResponseFormatDto(此处略)



结果示例







-------------------------------------
以上就是jwt的简单介绍以及应用。但是在实际项目中(特别是微服务流行的当下),用户验证、token管理一般不会在业务项目中实现的,基本上都是建立用户中心管理用户,鉴权用户信息,生成token等。
一般用Identity 4实现的,实际的业务项目则是提供token参数传入,在用户中心中验证。

posted on 2020-05-05 23:22  john_yong  阅读(2796)  评论(0编辑  收藏  举报

导航