
文章目录开启鉴权和授权Cookie登录配置测试整合JWT配置测试刷新token添加UserRefreshTokenManager修改login方法swagger添加jwt功能开启鉴权和授权在OnApplicationInitialization里添加鉴权和授权app.UseRouting();app.UseAuthentication();//身份认证我是谁app.UseAuthorization();//身份授权我的权限app.UseConfiguredEndpoints();Cookie登录适合mvc模式配置在ConfigureServices里添加cookie验证services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options{//登录失败后重定向页面//后面会跟着QueryParam ReturnUrl?表示从哪个链接调过来的//这样登录成功以后就可以调到原页面了options.LoginPath/Home/Index;// 设置Cookie的过期时间为7天options.ExpireTimeSpanTimeSpan.FromDays(3);//打开滑动延期实现连续3天不登录cookie自动删除要求用户重新登录options.SlidingExpirationtrue;});登录方法[HttpPost]publicasyncTaskIActionResultLogin([FromBody]Useruser){//添加用户名密码验证逻辑varclaimsnewListClaim{new(ClaimTypes.Name,me),};varroleListnewListstring{Admin};//从数据库拿到用户所有的角色foreach(varroleinroleList){claims.Add(new(ClaimTypes.Role,role));}varclaimsIdentitynewClaimsIdentity(claims,CookieAuthenticationDefaults.AuthenticationScheme);varrememberMetrue;varauthPropertiesnewAuthenticationProperties{IsPersistentrememberMe,// 根据用户选择是否记住登录状态设置过期时间ExpiresUtcrememberMe?DateTimeOffset.UtcNow.AddDays(7):null//token的有效期为7天};awaitHttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,newClaimsPrincipal(claimsIdentity),authProperties);returnRedirectToAction(Index);//登录成功后跳回首页}简单的登录页面formactionUrl.Action(Login,Home)methodpostHtml.AntiForgeryToken()buttontypesubmit登录/button/form将ICurrentUser注入进controllerpublicclassHomeController:Controller{privatereadonlyILoggerHomeController_logger;privatereadonlyICurrentUser_currentUser;publicHomeController(ILoggerHomeControllerlogger,ICurrentUseruser){_loggerlogger;_currentUseruser;}做一个需要Admin权限的页面[Authorize(RolesAdmin,Staff)]//在一起逗号分割是“或”//[Authorize(Roles Staff)] 另起一行是“且”publicIActionResultAdminAllow(){_logger.LogInformation(进来了);_logger.LogInformation($当前用户是{_currentUser.UserName});//拿到了mereturnRedirectToAction(Index);}测试进入首页后直接访问http://localhost:5062/Home/AdminAllow被重定向了点击登录按钮登录成功后返回首页查看cookie查看log日志整合JWT添加Microsoft.AspNetCore.Authentication.JwtBearer包配置在appsettings.json里添加JWT配置JwtSettings:{SecretKey:0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ,Issuer:your_issuer,Audience:your_audience,ExpireMinutes:60}在module里创建ConfigureAuthentication封装验证配置privatevoidConfigureAuthentication(IServiceCollectionservices,IConfigurationconfig){services.AddAuthentication(options{options.DefaultSchemeDualScheme;}).AddPolicyScheme(DualScheme,Cookie or JWT,options{options.ForwardDefaultSelectorcontext{// 根据请求头或路径选择认证方式if(context.Request.Headers.Authorization.Any(xx.StartsWith(Bearer ))){returnJwtBearerDefaults.AuthenticationScheme;}else{returnCookieAuthenticationDefaults.AuthenticationScheme;}};}).AddCookie(options{//登录失败后重定向页面//后面会跟着QueryParam ReturnUrl?表示从哪个链接调过来的//这样登录成功以后就可以调到原页面了options.LoginPath/Home/Index;// 设置Cookie的过期时间为3天options.ExpireTimeSpanTimeSpan.FromDays(3);//打开滑动延期实现连续3天不登录cookie自动删除要求用户重新登录options.SlidingExpirationtrue;}).AddJwtBearer(JwtBearerDefaults.AuthenticationScheme,options{options.TokenValidationParametersnewTokenValidationParameters{ValidateIssuertrue,ValidateAudiencetrue,ValidateLifetimetrue,ValidateIssuerSigningKeytrue,ValidIssuerconfig[JwtSettings:Issuer],ValidAudienceconfig[JwtSettings:Audience],IssuerSigningKeynewSymmetricSecurityKey(Encoding.UTF8.GetBytes(config[JwtSettings:SecretKey])),// 确保角色声明正确映射RoleClaimTypeClaimTypes.Role};});}ConfigureServices里调用ConfigureAuthenticationpublicoverridevoidConfigureServices(ServiceConfigurationContextcontext){varservicescontext.Services;varconfigservices.GetConfiguration();ConfigureAuthentication(services,config);ConfigureSwagger(services);}创建登录APIpublicIActionResultPostLogin(){varidGuidGenerator.Create().ToString();varclaimsnew[]{newClaim(AbpClaimTypes.UserName,me),//用户名newClaim(AbpClaimTypes.Role,Admin),//角色可多个newClaim(AbpClaimTypes.Role,SuperUser),newClaim(AbpClaimTypes.UserId,id)//user id};varkeynewSymmetricSecurityKey(Encoding.UTF8.GetBytes(_config[JwtSettings:SecretKey]));varcredentialsnewSigningCredentials(key,SecurityAlgorithms.HmacSha256);//因为256所以字符串长度至少32位varminutesint.Parse(_config[JwtSettings:ExpireMinutes]);vartokennewJwtSecurityToken(issuer:_config[JwtSettings:Issuer],audience:_config[JwtSettings:Audience],claims:claims,expires:DateTime.UtcNow.AddMinutes(minutes),signingCredentials:credentials);returnnewJsonResult(new{tokennewJwtSecurityTokenHandler().WriteToken(token),idid});//可以显式地传给前端也可以让前端自己去解token}创建带权限验证的API[Authorize(RolesAdmin)]publicIActionResultGetAccess(){Logger.LogDebug(JsonConvert.SerializeObject(CurrentUser,Formatting.Indented));}测试访问接口获取token带token访问刷新token添加UserRefreshTokenManager这里使用EasyCaching.SQLite做缓存框架。正式项目可以用IDistributedCache稍作修改即可。publicclassUserRefreshTokenManager:DomainService{privatereadonlyIConfiguration_config;privatereadonlyIGuidGenerator_guidGenerator;privatereadonlyIEasyCachingProvider_cachingProvider;publicUserRefreshTokenManager(IConfigurationconfig,IGuidGeneratorguidGenerator,IEasyCachingProvidercachingProvider){_configconfig;_guidGeneratorguidGenerator;_cachingProvidercachingProvider;}publicasyncTaskGuidGenerateRefreshToken(stringusername){varrefreshTokenStr_guidGenerator.Create();varexpireTimeTimeSpan.FromHours(int.Parse(_config[JwtSettings:RefreshTokenExpireHours]);await_cachingProvider.SetAsync(username,refreshTokenStr,expireTime);returnrefreshTokenStr;}publicstringGenerateToken(stringusername){varclaimsnew[]{newClaim(ClaimTypes.Name,me),newClaim(ClaimTypes.Role,Admin)};//用户示例varkeynewSymmetricSecurityKey(Encoding.UTF8.GetBytes(_config[JwtSettings:SecretKey]));varcredentialsnewSigningCredentials(key,SecurityAlgorithms.HmacSha256);//因为256所以字符串长度至少32位varminutesint.Parse(_config[JwtSettings:ExpireMinutes]);vartokennewJwtSecurityToken(issuer:_config[JwtSettings:Issuer],audience:_config[JwtSettings:Audience],claims:claims,expires:DateTime.UtcNow.AddMinutes(minutes),signingCredentials:credentials);returnnewJwtSecurityTokenHandler().WriteToken(token);}publicasyncTask(string,Guid)RefreshTokenAsync(GuidtokenStr,stringusername){varoldTokenawait_cachingProvider.GetAsyncGuid(username);if(!oldToken.HasValue||oldToken.Value!tokenStr){thrownewUserFriendlyException($Refresh token{tokenStr}is invalid!);}else{varnewTokenGenerateToken(username);varnewRefreshTokenawaitGenerateRefreshToken(username);return(newToken,newRefreshToken);}}}修改login方法publicvirtualasyncTaskIActionResultPostLogin(){varuserQawait_userDb.GetQueryableAsync();varuseruserQ.Where(uu.UsernameAdmin).FirstOrDefault();vartoken_userRefreshTokenManager.GenerateToken(user.Username);varrefreshTokenawait_userRefreshTokenManager.GenerateRefreshToken(user.Username);vartokenResponsenew{token,refreshToken,usernameuser.Username,};returnnewJsonResult(tokenResponse);}publicvirtualasyncTaskIActionResultPostRefreshToken([FromForm]GuidoldToken,[FromForm]stringusername){var(token,refreshToken)await_userRefreshTokenManager.RefreshTokenAsync(oldToken,username);vartokenResponsenew{token,refreshToken,username,};returnnewJsonResult(tokenResponse);}前端存储这两个tokenswagger添加jwt功能修改AddAbpSwaggerGen方法services.AddAbpSwaggerGen(options{options.SwaggerDoc(v1,newOpenApiInfo{TitleTest API,Versionv1});options.DocInclusionPredicate((docName,description)true);options.CustomSchemaIds(typetype.FullName);#region登录验证options.AddSecurityDefinition(Bearer,newOpenApiSecurityScheme{NameAuthorization,TypeSecuritySchemeType.Http,SchemeBearer,BearerFormatJWT,InParameterLocation.Header,Description请输入 JWT Token});// 全局应用该安全方案可选也可以只对特定操作应用options.AddSecurityRequirement(newOpenApiSecurityRequirement{{newOpenApiSecurityScheme{ReferencenewOpenApiReference{TypeReferenceType.SecurityScheme,IdBearer}},Array.Emptystring()}});#endregion});重启项目发现swagger页面右上角多了一个Authorize按钮在点击后的弹窗内直接输入token点Authorize会把token存在前端每次访问的时候都带上。