.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) 编辑 收藏 举报