ASP.Net MVC登录及授权
2026/7/17 16:32:49 网站建设 项目流程

文章目录

  • 开启鉴权和授权
  • 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.ExpireTimeSpan=TimeSpan.FromDays(3);//打开滑动延期,实现连续3天不登录,cookie自动删除,要求用户重新登录options.SlidingExpiration=true;});
  • 登录方法
[HttpPost]publicasyncTask<IActionResult>Login([FromBody]Useruser){//添加用户名密码验证逻辑varclaims=newList<Claim>{new(ClaimTypes.Name,"me"),};varroleList=newList<string>{"Admin"};//从数据库拿到用户所有的角色foreach(varroleinroleList){claims.Add(new(ClaimTypes.Role,role));}varclaimsIdentity=newClaimsIdentity(claims,CookieAuthenticationDefaults.AuthenticationScheme);varrememberMe=true;varauthProperties=newAuthenticationProperties{IsPersistent=rememberMe,// 根据用户选择是否记住登录状态设置过期时间ExpiresUtc=rememberMe?DateTimeOffset.UtcNow.AddDays(7):null//token的有效期为7天};awaitHttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,newClaimsPrincipal(claimsIdentity),authProperties);returnRedirectToAction("Index");//登录成功后跳回首页}
  • 简单的登录页面
<formaction="@Url.Action("Login","Home")"method="post">@Html.AntiForgeryToken()<buttontype="submit">登录</button></form>
  • 将ICurrentUser注入进controller
publicclassHomeController:Controller{privatereadonlyILogger<HomeController>_logger;privatereadonlyICurrentUser_currentUser;publicHomeController(ILogger<HomeController>logger,ICurrentUseruser){_logger=logger;_currentUser=user;}
  • 做一个需要Admin权限的页面
[Authorize(Roles="Admin,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.DefaultScheme="DualScheme";}).AddPolicyScheme("DualScheme","Cookie or JWT",options=>{options.ForwardDefaultSelector=context=>{// 根据请求头或路径选择认证方式if(context.Request.Headers.Authorization.Any(x=>x.StartsWith("Bearer "))){returnJwtBearerDefaults.AuthenticationScheme;}else{returnCookieAuthenticationDefaults.AuthenticationScheme;}};}).AddCookie(options=>{//登录失败后重定向页面//后面会跟着QueryParam ReturnUrl=?,表示从哪个链接调过来的//这样登录成功以后就可以调到原页面了options.LoginPath="/Home/Index";// 设置Cookie的过期时间为3天options.ExpireTimeSpan=TimeSpan.FromDays(3);//打开滑动延期,实现连续3天不登录,cookie自动删除,要求用户重新登录options.SlidingExpiration=true;}).AddJwtBearer(JwtBearerDefaults.AuthenticationScheme,options=>{options.TokenValidationParameters=newTokenValidationParameters{ValidateIssuer=true,ValidateAudience=true,ValidateLifetime=true,ValidateIssuerSigningKey=true,ValidIssuer=config["JwtSettings:Issuer"],ValidAudience=config["JwtSettings:Audience"],IssuerSigningKey=newSymmetricSecurityKey(Encoding.UTF8.GetBytes(config["JwtSettings:SecretKey"])),// 确保角色声明正确映射RoleClaimType=ClaimTypes.Role};});}
  • ConfigureServices里调用ConfigureAuthentication
publicoverridevoidConfigureServices(ServiceConfigurationContextcontext){varservices=context.Services;varconfig=services.GetConfiguration();ConfigureAuthentication(services,config);ConfigureSwagger(services);}
  • 创建登录API
publicIActionResultPostLogin(){varid=GuidGenerator.Create().ToString();varclaims=new[]{newClaim(AbpClaimTypes.UserName,"me"),//用户名newClaim(AbpClaimTypes.Role,"Admin"),//角色可多个newClaim(AbpClaimTypes.Role,"SuperUser"),newClaim(AbpClaimTypes.UserId,id)//user id};varkey=newSymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["JwtSettings:SecretKey"]));varcredentials=newSigningCredentials(key,SecurityAlgorithms.HmacSha256);//因为256,所以字符串长度至少32位varminutes=int.Parse(_config["JwtSettings:ExpireMinutes"]);vartoken=newJwtSecurityToken(issuer:_config["JwtSettings:Issuer"],audience:_config["JwtSettings:Audience"],claims:claims,expires:DateTime.UtcNow.AddMinutes(minutes),signingCredentials:credentials);returnnewJsonResult(new{token=newJwtSecurityTokenHandler().WriteToken(token),id=id});//可以显式地传给前端,也可以让前端自己去解token}
  • 创建带权限验证的API
[Authorize(Roles="Admin")]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){_config=config;_guidGenerator=guidGenerator;_cachingProvider=cachingProvider;}publicasyncTask<Guid>GenerateRefreshToken(stringusername){varrefreshTokenStr=_guidGenerator.Create();varexpireTime=TimeSpan.FromHours(int.Parse(_config["JwtSettings:RefreshTokenExpireHours"]);await_cachingProvider.SetAsync(username,refreshTokenStr,expireTime);returnrefreshTokenStr;}publicstringGenerateToken(stringusername){varclaims=new[]{newClaim(ClaimTypes.Name,"me"),newClaim(ClaimTypes.Role,"Admin")};//用户示例varkey=newSymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["JwtSettings:SecretKey"]));varcredentials=newSigningCredentials(key,SecurityAlgorithms.HmacSha256);//因为256,所以字符串长度至少32位varminutes=int.Parse(_config["JwtSettings:ExpireMinutes"]);vartoken=newJwtSecurityToken(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){varoldToken=await_cachingProvider.GetAsync<Guid>(username);if(!oldToken.HasValue||oldToken.Value!=tokenStr){thrownewUserFriendlyException($"Refresh token{tokenStr}is invalid!");}else{varnewToken=GenerateToken(username);varnewRefreshToken=awaitGenerateRefreshToken(username);return(newToken,newRefreshToken);}}}

修改login方法

publicvirtualasyncTask<IActionResult>PostLogin(){varuserQ=await_userDb.GetQueryableAsync();varuser=userQ.Where(u=>u.Username=="Admin").FirstOrDefault();vartoken=_userRefreshTokenManager.GenerateToken(user.Username);varrefreshToken=await_userRefreshTokenManager.GenerateRefreshToken(user.Username);vartokenResponse=new{token,refreshToken,username=user.Username,};returnnewJsonResult(tokenResponse);}publicvirtualasyncTask<IActionResult>PostRefreshToken([FromForm]GuidoldToken,[FromForm]stringusername){var(token,refreshToken)=await_userRefreshTokenManager.RefreshTokenAsync(oldToken,username);vartokenResponse=new{token,refreshToken,username,};returnnewJsonResult(tokenResponse);}

前端存储这两个token

swagger添加jwt功能

修改AddAbpSwaggerGen方法

services.AddAbpSwaggerGen(options=>{options.SwaggerDoc("v1",newOpenApiInfo{Title="Test API",Version="v1"});options.DocInclusionPredicate((docName,description)=>true);options.CustomSchemaIds(type=>type.FullName);#region登录验证options.AddSecurityDefinition("Bearer",newOpenApiSecurityScheme{Name="Authorization",Type=SecuritySchemeType.Http,Scheme="Bearer",BearerFormat="JWT",In=ParameterLocation.Header,Description="请输入 JWT Token"});// 全局应用该安全方案(可选:也可以只对特定操作应用)options.AddSecurityRequirement(newOpenApiSecurityRequirement{{newOpenApiSecurityScheme{Reference=newOpenApiReference{Type=ReferenceType.SecurityScheme,Id="Bearer"}},Array.Empty<string>()}});#endregion});

重启项目,发现swagger页面右上角多了一个Authorize按钮

在点击后的弹窗内直接输入token

点Authorize会把token存在前端,每次访问的时候都带上。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询