• C# 高级 <一>


    JWT:全称是JSON Web Token是目前最流行的跨域身份验证、分布式登录、单点登录等解决方案。

     通俗地来讲,JWT是能代表用户身份的令牌,可以使用JWT令牌在api接口中校验用户的身份以确认用户是否有访问api的权限。

    授权:这是使用JWT的最常见方案。一旦用户登录,每个后续请求将包括JWT,允许用户访问该令牌允许的路由,服务和资源。

    在身份验证中,当用户使用其凭据成功登录时,将返回JSON Web令牌。由于令牌是凭证,因此必须非常小心以防止出现安全问题。一般情况下,您不应该将令牌保留的时间超过要求。

    每当用户想要访问受保护的路由或资源时,用户代理应该使用承载模式发送JWT,通常在Authorization标头中,标题的内容应如下所示:

    Authorization: Bearer

    1、应用程序向授权服务器请求授权;

    2、校验用户身份,校验成功,返回token;

    3、应用程序使用访问令牌访问受保护的资源。

     JWT的实现方式是将用户信息存储在客户端,服务端不进行保存。每次请求都把令牌带上以校验用户登录状态,这样服务就变成了无状态的,服务器集群也很好扩展。

    更多理论知识可以查看官网,或者查看相关网友的文章,如下推荐文章:

    在nuget里面引用jwt集成的程序包,这里需要注意的是,如果你用的是.NET Core 3.1的框架的话,程序包版本选择3.1.7

    Microsoft.AspNetCore.Authentication.JwtBearer

    添加数据访问模拟api,新建控制器ValuesController

    其中api/value1是可以直接访问的,api/value2添加了权限校验特性标签 [Authorize]

    1. using Microsoft.AspNetCore.Authentication;
    2. using Microsoft.AspNetCore.Authorization;
    3. using Microsoft.AspNetCore.Mvc;
    4. using System;
    5. using System.Collections.Generic;
    6. using System.Linq;
    7. using System.Security.Claims;
    8. using System.Threading.Tasks;
    9. namespace jwtWebAPI.Controllers
    10. {
    11. [ApiController]
    12. public class ValuesController : ControllerBase
    13. {
    14. [HttpGet]
    15. [Route("api/values1")]
    16. public ActionResult<IEnumerable<string>> values1()
    17. {
    18. return new string[] { "value1", "value1" };
    19. }
    20. /**
    21. * 该接口用Authorize特性做了权限校验,如果没有通过权限校验,则http返回状态码为401
    22. * 调用该接口的正确姿势是:
    23. * 1.登陆,调用api/Auth接口获取到token
    24. * 2.调用该接口 api/value2 在请求的Header中添加参数 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOiIxNTYwMzM1MzM3IiwiZXhwIjoxNTYwMzM3MTM3LCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiemhhbmdzYW4iLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjUwMDAiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjUwMDAifQ.1S-40SrA4po2l4lB_QdzON_G5ZNT4P_6U25xhTcl7hI
    25. * Bearer后面有空格,且后面是第一步中接口返回的token值
    26. * */
    27. [HttpGet]
    28. [Route("api/value2")]
    29. [Authorize]
    30. public ActionResult<IEnumerable<string>> value2()
    31. {
    32. //这是获取自定义参数的方法
    33. var auth = HttpContext.AuthenticateAsync().Result.Principal.Claims;
    34. var userName = auth.FirstOrDefault(t => t.Type.Equals(ClaimTypes.NameIdentifier))?.Value;
    35. return new string[] { "访问成功:这个接口登陆过的用户都可以访问", $"userName={userName}" };
    36. }
    37. }
    38. }

    添加模拟登陆生成Token的api,新建控制器AuthController

    这里模拟一下登陆校验,只验证了用户密码不为空即通过校验,真实环境完善校验用户和密码的逻辑。

    1. using Microsoft.AspNetCore.Authorization;
    2. using Microsoft.AspNetCore.Mvc;
    3. using Microsoft.IdentityModel.Tokens;
    4. using System;
    5. using System.Collections.Generic;
    6. using System.IdentityModel.Tokens.Jwt;
    7. using System.Linq;
    8. using System.Security.Claims;
    9. using System.Text;
    10. using System.Threading.Tasks;
    11. namespace jwtWebAPI.Controllers
    12. {
    13. [ApiController]
    14. public class AuthController : Controller
    15. {
    16. /// <summary>
    17. /// 通过账号+密码获取Token
    18. /// </summary>
    19. /// <param name="userName"></param>
    20. /// <param name="pwd"></param>
    21. /// <returns>Token</returns>
    22. [AllowAnonymous]
    23. [HttpGet]
    24. [Route("api/auth")]
    25. public IActionResult GetToken(string userName, string pwd)
    26. {
    27. if (!string.IsNullOrEmpty(userName))
    28. {
    29. //每次登陆动态刷新
    30. Const.ValidAudience = userName + pwd + DateTime.Now.ToString();
    31. // push the user’s name into a claim, so we can identify the user later on.
    32. //这里可以随意加入自定义的参数,key可以自己随便起
    33. var claims = new[]
    34. {
    35. new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,
    36. new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddMinutes(3)).ToUnixTimeSeconds()}"),
    37. new Claim(ClaimTypes.NameIdentifier, userName)
    38. };
    39. //sign the token using a secret key.This secret will be shared between your API and anything that needs to check that the token is legit.
    40. var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Const.SecurityKey));
    41. var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
    42. //.NET Core’s JwtSecurityToken class takes on the heavy lifting and actually creates the token.
    43. var token = new JwtSecurityToken(
    44. //颁发者
    45. issuer: Const.Domain,
    46. //接收者
    47. audience: Const.ValidAudience,
    48. //过期时间(可自行设定,注意和上面的claims内部Exp参数保持一致)
    49. expires: DateTime.Now.AddMinutes(3),
    50. //签名证书
    51. signingCredentials: creds,
    52. //自定义参数
    53. claims: claims
    54. );
    55. return Ok(new
    56. {
    57. token = new JwtSecurityTokenHandler().WriteToken(token)
    58. });
    59. }
    60. else
    61. {
    62. return BadRequest(new { message = "username or password is incorrect." });
    63. }
    64. }
    65. }
    66. }

    Startup添加JWT验证的相关配置

    1. using Microsoft.AspNetCore.Authentication.JwtBearer;
    2. using Microsoft.AspNetCore.Builder;
    3. using Microsoft.AspNetCore.Hosting;
    4. using Microsoft.AspNetCore.HttpsPolicy;
    5. using Microsoft.AspNetCore.Mvc;
    6. using Microsoft.Extensions.Configuration;
    7. using Microsoft.Extensions.DependencyInjection;
    8. using Microsoft.Extensions.Hosting;
    9. using Microsoft.Extensions.Logging;
    10. using Microsoft.IdentityModel.Tokens;
    11. using System;
    12. using System.Collections.Generic;
    13. using System.Linq;
    14. using System.Text;
    15. using System.Threading.Tasks;
    16. namespace jwtWebAPI
    17. {
    18. public class Startup
    19. {
    20. public Startup(IConfiguration configuration)
    21. {
    22. Configuration = configuration;
    23. }
    24. public IConfiguration Configuration { get; }
    25. // This method gets called by the runtime. Use this method to add services to the container.
    26. public void ConfigureServices(IServiceCollection services)
    27. {
    28. //添加jwt验证:
    29. services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    30. .AddJwtBearer(options => {
    31. options.TokenValidationParameters = new TokenValidationParameters
    32. {
    33. ValidateLifetime = true,//是否验证失效时间
    34. ClockSkew = TimeSpan.FromSeconds(30), //时间偏移量(允许误差时间)
    35. ValidateAudience = true,//是否验证Audience(验证之前的token是否失效)
    36. //ValidAudience = Const.GetValidudience(),//Audience
    37. //这里采用动态验证的方式,在重新登陆时,刷新token,旧token就强制失效了
    38. AudienceValidator = (m, n, z) =>
    39. {
    40. return m != null && m.FirstOrDefault().Equals(Const.ValidAudience);
    41. },
    42. ValidateIssuer = true,//是否验证Issuer(颁发者)
    43. ValidAudience = Const.Domain,//Audience 【Const是新建的一个常量类】 接收者
    44. ValidIssuer = Const.Domain,//Issuer,这两项和前面签发jwt的设置一致 颁发者
    45. ValidateIssuerSigningKey = true,//是否验证SecurityKey
    46. IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Const.SecurityKey))//拿到秘钥SecurityKey
    47. };
    48. options.Events = new JwtBearerEvents
    49. {
    50. OnAuthenticationFailed = context =>
    51. {
    52. //Token expired
    53. if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
    54. {
    55. context.Response.Headers.Add("Token-Expired", "true");
    56. }
    57. return Task.CompletedTask;
    58. }
    59. };
    60. });
    61. services.AddControllers();
    62. }
    63. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    64. public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    65. {
    66. //添加jwt验证
    67. app.UseAuthentication();
    68. if (env.IsDevelopment())
    69. {
    70. app.UseDeveloperExceptionPage();
    71. }
    72. app.UseHttpsRedirection();
    73. app.UseRouting();
    74. app.UseAuthorization();
    75. app.UseEndpoints(endpoints =>
    76. {
    77. endpoints.MapControllers();
    78. });
    79. }
    80. }
    81. }

    创建常量类Const

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Threading.Tasks;
    5. namespace jwtWebAPI
    6. {
    7. public class Const
    8. {
    9. /// <summary>
    10. /// 这里为了演示,写死一个密钥。实际生产环境可以从配置文件读取,这个是用网上工具随便生成的一个密钥(md5或者其他都可以)
    11. /// </summary>
    12. public const string SecurityKey = "48754F4C58F9EA428FE09D714E468211";
    13. /// <summary>
    14. /// 站点地址(颁发者、接受者),这里测试和当前本地运行网站相同,实际发到正式环境应为域名地址
    15. /// </summary>
    16. public const string Domain = "https://localhost:44345";
    17. /// <summary>
    18. /// 受理人,之所以弄成可变的是为了用接口动态更改这个值以模拟强制Token失效
    19. /// 真实业务场景可以在数据库或者redis存一个和用户id相关的值,生成token和验证token的时候获取到持久化的值去校验
    20. /// 如果重新登陆,则刷新这个值
    21. /// </summary>
    22. public static string ValidAudience;
    23. }
    24. }

    JWT登录授权测试成功

    返回了状态码401,也就是未经授权:访问由于凭据无效被拒绝。 说明JWT校验生效了,我们的接口收到了保护。

    调用模拟登陆授权接口:https://localhost:44345/api/auth?userName=xiongze&pwd=123456

    这里的用户密码是随便写的,因为我们模拟登陆只是校验了下非空,因此写什么都能通过。

    然后我们得到了一个xxx.yyy.zzz 格式的 token 值。我们把token复制出来。

    在刚才401的接口(https://localhost:44345/api/values2)请求header中添加JWT的参数,把我们的token加上去

    再次调用我们的模拟数据接口,但是这次我们加了一个header,KEY:Authorization     Value:Bearer Tokne的值

    这里需要注意 Bearer 后面是有一个空格的,然后就是我们上一步获取到的token,

    得到返回值,正确授权成功,我们是支持自定义返回参数的,上面代码里面有相关内容,比如用户名这些不敏感的信息可以带着返回。

    等token设置的过期时间到了,或者重新生成了新的Token,没有及时更新,那么我们的授权也到期,401,

    升级操作:接口权限隔离

    上面的操作是所有登录授权成功的角色都可以进行调用所有接口,那么我们现在想要进行接口隔离限制,

    也就是说,虽然授权登录了,但是我这个接口是指定权限访问的。

    比如说:删除接口只能管理员角色操作,那么其他角色虽然授权登录了,但是没有权限调用删除接口。

    我们在原来的操作进行改造升级看一下。

    添加类

    新建一个AuthManagement文件夹,添加PolicyRequirement类PolicyHandler类

    PolicyRequirement类:

    1. using Microsoft.AspNetCore.Authorization;
    2. using Microsoft.AspNetCore.Http;
    3. using System;
    4. using System.Collections.Generic;
    5. using System.Linq;
    6. using System.Threading.Tasks;
    7. namespace jwtWebAPI.AuthManagement
    8. {
    9. /// <summary>
    10. /// 权限承载实体
    11. /// </summary>
    12. public class PolicyRequirement : IAuthorizationRequirement
    13. {
    14. /// <summary>
    15. /// 用户权限集合
    16. /// </summary>
    17. public List<UserPermission> UserPermissions { get; private set; }
    18. /// <summary>
    19. /// 无权限action
    20. /// </summary>
    21. public string DeniedAction { get; set; }
    22. /// <summary>
    23. /// 构造
    24. /// </summary>
    25. public PolicyRequirement()
    26. {
    27. //没有权限则跳转到这个路由
    28. DeniedAction = new PathString("/api/nopermission");
    29. //用户有权限访问的路由配置,当然可以从数据库获取
    30. UserPermissions = new List<UserPermission> {
    31. new UserPermission { Url="/api/values3", UserName="admin"},
    32. };
    33. }
    34. }
    35. /// <summary>
    36. /// 用户权限承载实体
    37. /// </summary>
    38. public class UserPermission
    39. {
    40. /// <summary>
    41. /// 用户名
    42. /// </summary>
    43. public string UserName { get; set; }
    44. /// <summary>
    45. /// 请求Url
    46. /// </summary>
    47. public string Url { get; set; }
    48. }
    49. }

    PolicyHandler类(注意2.x和3.x的区别)

    1. using Microsoft.AspNetCore.Authorization;
    2. using Microsoft.AspNetCore.Http;
    3. using System;
    4. using System.Collections.Generic;
    5. using System.Linq;
    6. using System.Security.Claims;
    7. using System.Threading.Tasks;
    8. namespace jwtWebAPI.AuthManagement
    9. {
    10. public class PolicyHandler : AuthorizationHandler<PolicyRequirement>
    11. {
    12. private readonly IHttpContextAccessor _httpContextAccessor;
    13. public PolicyHandler(IHttpContextAccessor httpContextAccessor)
    14. {
    15. _httpContextAccessor = httpContextAccessor;
    16. }
    17. protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PolicyRequirement requirement)
    18. {
    19. //赋值用户权限
    20. var userPermissions = requirement.UserPermissions;
    21. var httpContext = _httpContextAccessor.HttpContext;
    22. //请求Url
    23. var questUrl = httpContext.Request.Path.Value.ToUpperInvariant();
    24. //是否经过验证
    25. var isAuthenticated = httpContext.User.Identity.IsAuthenticated;
    26. if (isAuthenticated)
    27. {
    28. if (userPermissions.GroupBy(g => g.Url).Any(w => w.Key.ToUpperInvariant() == questUrl))
    29. {
    30. //用户名
    31. var userName = httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.NameIdentifier).Value;
    32. if (userPermissions.Any(w => w.UserName == userName && w.Url.ToUpperInvariant() == questUrl))
    33. {
    34. context.Succeed(requirement);
    35. }
    36. else
    37. {
    38. 无权限跳转到拒绝页面
    39. //httpContext.Response.Redirect(requirement.DeniedAction);
    40. return Task.CompletedTask;
    41. }
    42. }
    43. else
    44. {
    45. context.Succeed(requirement);
    46. }
    47. }
    48. return Task.CompletedTask;
    49. }
    50. }
    51. }

    添加指定角色

    在 AuthController 控制器的GetToken授权加入自定义的参数,如下

    new Claim("Role", userName)  //这里是角色,我使用登录账号admin代替

     在 AuthController 控制器里面添加无权限访问的方法

    1. [AllowAnonymous]
    2. [HttpGet]
    3. [Route("api/nopermission")]
    4. public IActionResult NoPermission()
    5. {
    6.      return Forbid("No Permission!");
    7. }

    2023-12.19日补充

    在需要jwt验证控制器上添加 [ApiAuthorizeFilterAttribute] 特性

    新建ApiAuthorizeFilterAttribute 过滤器类 并继承ActionFilterAttribute类,每次请求都要经过,在OnActionExecuting验证token是否有效

    1. using HBAirWebAPI.Controllers;
    2. using Microsoft.AspNetCore.Authorization;
    3. using Microsoft.AspNetCore.Mvc;
    4. using Microsoft.AspNetCore.Mvc.Controllers;
    5. using Microsoft.AspNetCore.Mvc.Filters;
    6. using Microsoft.IdentityModel.Tokens;
    7. using Sys.Model;
    8. using System;
    9. using System.Collections.Generic;
    10. using System.IdentityModel.Tokens.Jwt;
    11. using System.Linq;
    12. using System.Security.Claims;
    13. using System.Threading.Tasks;
    14. namespace HBAirWebAPI.Common
    15. {
    16. public class ApiAuthorizeFilterAttribute : ActionFilterAttribute
    17. {
    18. public override void OnActionExecuting(ActionExecutingContext context)
    19. {
    20. Microsoft.AspNetCore.Http.IHeaderDictionary dic = context.HttpContext.Request.Headers;
    21. var token = dic["Authorization"].ToString();
    22. if (token == null)
    23. {
    24. context.Result = new OkObjectResult(new { code = 401, messge = "用户权限已失效!" });
    25. }
    26. else
    27. {
    28. //token = token.Replace("Bearer", "").Trim();string secretKey, string issuer, string audience
    29. //检验token JWT 签名有效、时间有效.
    30. ClaimsPrincipal jwtUsr = ClaimsPrincipals.ValidateToken(token, ConfigurationManager.GetSection("Authentication:SecurityKey"), ConfigurationManager.GetSection("Authentication:Issure"), ConfigurationManager.GetSection("Authentication:Audience"));
    31. if (jwtUsr == null)
    32. {
    33. context.Result = new OkObjectResult(new { code = 401, messge = "用户权限已失效!" });
    34. }
    35. }
    36. // 如果不是一个控制器方法则直接返回
    37. if (!(context.ActionDescriptor is ControllerActionDescriptor action))
    38. {
    39. return;
    40. }
    41. var controllerActionDescriptor = context.ActionDescriptor as Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor;
    42. 如果控制器上加了[AllowAnonymous],就跳过权限检查
    43. if (controllerActionDescriptor.ControllerTypeInfo.IsDefined(typeof(AllowAnonymousAttribute), true))
    44. {
    45. return;
    46. }
    47. //如果方法上加了[AllowAnonymous],就跳过权限检查
    48. if (action.MethodInfo.GetCustomAttributes(typeof(AllowAnonymousAttribute), false).Any())
    49. return;
    50. }
    51. }
    52. }

    其中ClaimsPrincipals类代码如下:

    1. using Microsoft.IdentityModel.Tokens;
    2. using System;
    3. using System.Collections.Generic;
    4. using System.IdentityModel.Tokens.Jwt;
    5. using System.Linq;
    6. using System.Security.Claims;
    7. using System.Text;
    8. using System.Threading.Tasks;
    9. namespace HBAirWebAPI.Common
    10. {
    11. public class ClaimsPrincipals
    12. {
    13. public static ClaimsPrincipal ValidateToken(string token, string secretKey, string issuer, string audience)
    14. {
    15. var validationParameters = new TokenValidationParameters
    16. {
    17. ValidateIssuerSigningKey = true,
    18. IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)),
    19. ValidateIssuer = true,
    20. ValidIssuer = issuer,
    21. ValidateAudience = true,
    22. ValidAudience = audience,
    23. ValidateLifetime = true,
    24. };
    25. var handler = new JwtSecurityTokenHandler();
    26. ClaimsPrincipal principal;
    27. try
    28. {
    29. principal = handler.ValidateToken(token, validationParameters, out _);
    30. // You can access the claims of the token using:
    31. //principal.Claims
    32. return principal;
    33. }
    34. catch (Exception ex)
    35. {
    36. // Token validation failed
    37. return null;
    38. }
    39. }
    40. }
    41. }

     ClaimsPrincipals.ValidateToken 方法验证是否有效。无效则不通过。不能调用接口。

    2023-12.19日补充 结束

    修改Startup配置

    在startup.cs的ConfigureServices 方法里面添加策略鉴权模式、添加JWT Scheme、注入授权Handler 

    修改后的文件如下

    1. using jwtWebAPI.AuthManagement;
    2. using Microsoft.AspNetCore.Authentication.JwtBearer;
    3. using Microsoft.AspNetCore.Authorization;
    4. using Microsoft.AspNetCore.Builder;
    5. using Microsoft.AspNetCore.Hosting;
    6. using Microsoft.AspNetCore.Http;
    7. using Microsoft.AspNetCore.HttpsPolicy;
    8. using Microsoft.AspNetCore.Mvc;
    9. using Microsoft.Extensions.Configuration;
    10. using Microsoft.Extensions.DependencyInjection;
    11. using Microsoft.Extensions.DependencyInjection.Extensions;
    12. using Microsoft.Extensions.Hosting;
    13. using Microsoft.Extensions.Logging;
    14. using Microsoft.IdentityModel.Tokens;
    15. using System;
    16. using System.Collections.Generic;
    17. using System.Linq;
    18. using System.Text;
    19. using System.Threading.Tasks;
    20. namespace jwtWebAPI
    21. {
    22. public class Startup
    23. {
    24. public Startup(IConfiguration configuration)
    25. {
    26. Configuration = configuration;
    27. }
    28. public IConfiguration Configuration { get; }
    29. // This method gets called by the runtime. Use this method to add services to the container.
    30. public void ConfigureServices(IServiceCollection services)
    31. {
    32. services
    33. //添加策略鉴权模式
    34. .AddAuthorization(options =>
    35. {
    36. options.AddPolicy("Permission", policy => policy.Requirements.Add(new PolicyRequirement()));
    37. })
    38. //添加JWT Scheme
    39. .AddAuthentication(s =>
    40. {
    41. s.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    42. s.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
    43. s.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    44. })
    45. //添加jwt验证:
    46. .AddJwtBearer(options => {
    47. options.TokenValidationParameters = new TokenValidationParameters
    48. {
    49. ValidateLifetime = true,//是否验证失效时间
    50. ClockSkew = TimeSpan.FromSeconds(30), //时间偏移量(允许误差时间)
    51. ValidateAudience = true,//是否验证Audience(验证之前的token是否失效)
    52. //ValidAudience = Const.GetValidudience(),//Audience
    53. //这里采用动态验证的方式,在重新登陆时,刷新token,旧token就强制失效了
    54. AudienceValidator = (m, n, z) =>
    55. {
    56. return m != null && m.FirstOrDefault().Equals(Const.ValidAudience);
    57. },
    58. ValidateIssuer = true,//是否验证Issuer(颁发者)
    59. ValidAudience = Const.Domain,//Audience 【Const是新建的一个常量类】 接收者
    60. ValidIssuer = Const.Domain,//Issuer,这两项和前面签发jwt的设置一致 颁发者
    61. ValidateIssuerSigningKey = true,//是否验证SecurityKey
    62. IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Const.SecurityKey))//拿到秘钥SecurityKey
    63. };
    64. options.Events = new JwtBearerEvents
    65. {
    66. OnAuthenticationFailed = context =>
    67. {
    68. //Token expired
    69. if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
    70. {
    71. context.Response.Headers.Add("Token-Expired", "true");
    72. }
    73. return Task.CompletedTask;
    74. }
    75. };
    76. });
    77. //注入授权Handler
    78. services.AddSingleton<IAuthorizationHandler, PolicyHandler>();
    79. //注入获取HttpContext
    80. services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    81. services.AddControllers();
    82. }
    83. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    84. public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    85. {
    86. //添加jwt验证
    87. app.UseAuthentication();
    88. if (env.IsDevelopment())
    89. {
    90. app.UseDeveloperExceptionPage();
    91. }
    92. app.UseHttpsRedirection();
    93. app.UseRouting();
    94. app.UseAuthorization();
    95. app.UseEndpoints(endpoints =>
    96. {
    97. endpoints.MapControllers();
    98. });
    99. }
    100. }
    101. }

    添加api访问的方法

    在 ValuesController控制器添加指定权限访问的方法,如下:

    1. /**
    2. * 这个接口必须用admin
    3. **/
    4. [HttpGet]
    5. [Route("api/values3")]
    6. [Authorize("Permission")]
    7. public ActionResult<IEnumerable<string>> values3()
    8. {
    9. //这是获取自定义参数的方法
    10. var auth = HttpContext.AuthenticateAsync().Result.Principal.Claims;
    11. var userName = auth.FirstOrDefault(t => t.Type.Equals(ClaimTypes.NameIdentifier))?.Value;
    12. var role = auth.FirstOrDefault(t => t.Type.Equals("Role"))?.Value;
    13. return new string[] { "访问成功:这个接口有管理员权限才可以访问", $"userName={userName}", $"Role={role}" };
    14. }

     不同权限测试访问

    我们同样的方法去模拟登录,https://localhost:44345/api/auth?userName=xiongze&pwd=123

    注意,账号先不用admin登录,然后用返回的token去请求我们刚刚添加的指定权限访问的接口,这个时候是没有权限访问的,因为这个是admin权限访问。

    我们同样的方法去模拟登录,https://localhost:44345/api/auth?userName=xiongze&pwd=123

    注意,账号先不用admin登录,然后用返回的token去请求我们刚刚添加的指定权限访问的接口,这个时候是没有权限访问的,因为这个是admin权限访问。

    我们同样的方法去模拟登录,https://localhost:44345/api/auth?userName=admin&pwd=123

    访问成功。

    完结。。。

  • 相关阅读:
    吴恩达2022机器学习专项课程C2W2:实验SoftMax
    RocketMQ的架构设计
    【二分查找】leetcode 240. 搜索二维矩阵 II
    SQL获取当前年月的每一天
    MySQL客户端与服务端建立连接抓包分析
    oradebug current_sql
    超实用!产品经理如何提高自己的工作效率?
    第一章《初学者问题大集合》第6节:IntelliJ IDEA的下载与安装
    Angular 怎么封装基础组件?
    LeetCode - 102. 二叉树的层序遍历;110. 平衡二叉树;098. 验证二叉搜索树
  • 原文地址:https://blog.csdn.net/qq_26695613/article/details/134051442