初学WebApi,为了实现登录,最开始的想法是加入Session,不过新建的WebApi项目中没有自动引入Session,然后在搜索资料时发现,WebApi最好使用主流验证模式JWT 来验证登录,这样可以适应多种验证环境 比如APP 移动Web 对外接口。
当然JWT也有缺点,比如它不像Session那样 用户请求后会刷新过期时间,这个需要手动配置代码去刷新ToKen。
关于什么是JWT 这里不再描述,详细可以见下面链接,这里只写代码实现
ASP.NET Core 认证与授权[4]:JwtBearer认证 - 雨夜朦胧 - 博客园
直接进入正题
新建一个 WebApi项目
我这里项目取名为 JWTTest
配置HTTPS 勾不勾感觉无所谓,我这里OpenAPI勾上,是为了自动创建Swagger 测试页的
项目的初始结构。
首先在NuGet 安装下面两个依赖包
1,JwtBearer
2,IdentityServer4.AccessTokenValidation
第一步:配置 appsettings.json
这步根据你自己的需求来配置,我这里就是把key 存在配置文件里,也可以存在数据库或者其他地方。
"lConfig_JWTOptions": { "Issuer": "http://localhost:44309", "Audience": "api", "key": "aaaaaaaaaaaaaaaaa" }
红色框就是配置代码
lConfig_JWTOptions 是自定义名字
第二步:配置 Startup.cs
顺带提一下 Startup.cs 就相当于Web.config ,就以前的xml 变成类的形式来配置。
1,先从配置文件里读出 自定义key
ConfigureServices 方法:
public void ConfigureServices(IServiceCollection services) { //获取配置文件中Config_JWTOptions的key var myKey= Configuration.GetSection("Config_JWTOptions").GetChildren().FirstOrDefault(a => a.Key.Equals("key")).Value; //开启 JWT 验证 services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(o => { o.TokenValidationParameters = new TokenValidationParameters { //配置JWT验证 NameClaimType = JwtClaimTypes.Name, RoleClaimType = JwtClaimTypes.Role, //这里是会跟JwtClaimTypes.Issuer校验,这里值我测试过 填个AAA啥的都可以 //只要跟JwtClaimTypes.Issuer的值保持一致就行了。 ValidIssuer = "http://localhost:44309", //这里是跟JwtClaimTypes.Audience 的值校验,也是可以随便填可以,保存一致就行。 ValidAudience = "api", IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(myKey)) // RequireSignedTokens = true, // SaveSigninToken = false, // ValidateActor = false, // 将下面两个参数设置为false,可以不验证Issuer和Audience,但是不建议这样做。 // ValidateAudience = true, // ValidateIssuer = true, // ValidateIssuerSigningKey = false, // 是否要求Token的Claims中必须包含Expires // RequireExpirationTime = true, // 允许的服务器时间偏移量 // ClockSkew = TimeSpan.FromSeconds(300), // //是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比 // ValidateLifetime = true }; }); services.AddControllers(); }
3,JWT使用起来
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseSwagger(); app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "JWTTest v1")); } app.UseRouting(); //使用JWT验证 app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
注意:app.UseXXXx() 是有先后顺序的,我这里是放在了UseRouting后面,UseAuthorization的前面。
第三步:控制器配置验证,我这里就直接用自动创建的控制器WeatherForecastController
可以先测试下 上面的JWT配置 有没有生效
先运行启动,请求一下WeatherForecast,请求成功是返回状态码200的。
这里之所以是成功,因为还没有给这个请求加上验证
1,给Get方法 加上[Authorize] 就会开启验证
然后再来请求一次测试下, 请求返回的状态码就是401了,没有权限。
2,开始配置生成Token, 新写一个方法 Login_GetToken,模拟登录一下
[HttpPost] public IActionResult Login_GetToken(String userName, String password) { //假设账号和密码都是demo 否则验证失败 if (!userName.Equals("demo") || !password.Equals("demo")) { return Unauthorized();//登录失败 返回状态码 401 } //登录成功,生成ToKen var tokenHandler = new JwtSecurityTokenHandler(); var authTime = DateTime.UtcNow; var expiresAt = authTime.AddDays(7); var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new Claim[] { new Claim(JwtClaimTypes.Audience, "api"), new Claim(JwtClaimTypes.Issuer, "http://localhost:44309"), new Claim(JwtClaimTypes.Id, "1001"), new Claim(JwtClaimTypes.Name, userName), // new Claim(JwtClaimTypes.Email, "[email protected]"),//根据需求填 //new Claim(JwtClaimTypes.PhoneNumber,"13600000000") }), Expires = expiresAt, SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.ASCII.GetBytes("aaaaaaaaaaaaaaaaa")), SecurityAlgorithms.HmacSha256Signature) }; var token = tokenHandler.CreateToken(tokenDescriptor); var tokenString = tokenHandler.WriteToken(token); return Ok(new { access_token = tokenString, token_type = "Bearer", profile = new { sid = "1001", name = userName, auth_time = new DateTimeOffset(authTime).ToUnixTimeSeconds(), expires_at = new DateTimeOffset(expiresAt).ToUnixTimeSeconds() } }); }
最后再测试一下登录:登录成功后会返回token
下次请求带上这个Token 就可以正常访问了。
最后:
如果要带上token去测试前面配置的Get()方法,需要先配置Swagger页的Authorize支持
在 Startup 中 ConfigureServices 方法:
services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "JWTTest", Version = "v1" }); //swagger启动JWT验证 var sec = new OpenApiSecurityScheme { Description = "JWT Authorization header using the Bearer scheme. Example: "Authorization: Bearer {token}"", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.Http, Scheme = "Bearer", BearerFormat = "JWT" }; //把所有方法配置为增加bearer头部信息 var securityRequirement = new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "bearerAuth" } }, new string[] {} } }; //注册到swagger中 c.AddSecurityDefinition("bearerAuth", sec); c.AddSecurityRequirement(securityRequirement); });
再次启动时,每个接口后面 就会有一把锁,就说明配置成功了。
点击锁,就可以带上token 去请求接口
这个Demo比较乱,不过初步的实现了JWT 验证,后期可以把生成Token封装一个类里。配合注入依赖和 appsettings.json 就可以把代码变的很整洁也容易维护了。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)