NetCore JWT token

在netcore中jwt使用场景很多,网上有很多的资料,这里不再累述,之后有机会会单独介绍,今天主要以实战为主。

1、create jwt token

 1 public interface IJwtTokenService
 2     {
 3         string GetJwtToken();
 4     }
 5 
 6     public class JwtTokenService : IJwtTokenService
 7     {
 8         private readonly IConfiguration _config;
 9         public JwtTokenService(IConfiguration config)
10         {
11             this._config = config;
12         }
13         public string GetJwtToken()
14         {
15             var claims = new List<Claim>()
16             {
17                 new Claim(JwtRegisteredClaimNames.Sub,"jwtsubvalue"),
18                 new Claim(JwtRegisteredClaimNames.Name,"jwtnamevalue"),
19                 new Claim("Scope","API"),
20                 new Claim("Role","Admin")
21             };
22             var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["JwtToken:SecretKey"]));
23             var credentials = new SigningCredentials(securityKey,SecurityAlgorithms.HmacSha256);
24             var issuer = _config["JwtToken:Issuer"];
25             var audience = _config["JwtToken:Audience"];
26             var expires = DateTime.Now.AddMinutes(Convert.ToDouble(_config["JwtToken:ExpiredMinutes"]));
27 
28             var jwtToken = new JwtSecurityToken(issuer, audience, claims: claims, notBefore: DateTime.Now, expires: expires, signingCredentials: credentials);
29             return new JwtSecurityTokenHandler().WriteToken(jwtToken);
30         }
31     }
jwt token

2、configuration中所需配置信息

1  "JwtToken": {
2     "SecretKey": "12345678901234567890123456789012",
3     "Issuer": "https://localhost:5000",
4     "Audience": "https://localhost:5000",
5     "ExpiredMinutes": 10
6   }

3、在Program中配置authentication

 1 var configuration = builder.Configuration;
 2 builder.Services.AddAuthentication(options =>
 3 {
 4     options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
 5     options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
 6 })
 7 .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
 8     {
 9         options.TokenValidationParameters = new TokenValidationParameters
10         {
11             ValidateIssuer = true,
12             ValidateAudience = true,
13             ValidateLifetime = true,
14             ValidateIssuerSigningKey = true,
15             ValidIssuer = configuration["JwtToken:Issuer"],
16             ValidAudience = configuration["JwtToken:Audience"],
17             IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["JwtToken:SecretKey"]))
18         };
19         options.Events = new JwtBearerEvents
20         {
21             OnTokenValidated = context =>
22             {
23                 var token = context.SecurityToken as JwtSecurityToken;
24                 var identity = context.Principal?.Identity as ClaimsIdentity;
25                 if (!string.IsNullOrEmpty(token?.Issuer))
26                     context.Success();
27                 else
28                     context.Fail($"Token invalid");
29                 return Task.CompletedTask;
30             },
31             OnAuthenticationFailed = context =>
32             {
33                 context.Fail(context.Exception);
34                 return Task.CompletedTask;
35             },
36             OnForbidden = context =>
37             {
38                 context.Fail("403 forbidden");
39                 return Task.CompletedTask;
40             },
41             OnChallenge = context =>
42             {
43                 var error = context.Error;
44                 return Task.CompletedTask;
45             },
46             OnMessageReceived = context =>
47             {
48                 var token = context.Token;
49                 return Task.CompletedTask;
50             }
51         };
52         //Configure authentication scheme forwarding to another scheme
53         options.ForwardDefaultSelector = context =>
54         {
55             if (context.Request.Headers.TryGetValue("x-api-type", out Microsoft.Extensions.Primitives.StringValues uiTokenType))
56                 return "CustomScheme";
57             return JwtBearerDefaults.AuthenticationScheme;
58         };
59     }).AddJwtBearer("CustomScheme", options =>
60     {
61         options.Authority = configuration["JwtToken:Issuer"];
62         options.TokenValidationParameters = new TokenValidationParameters
63         {
64             ValidateIssuer = true,
65             ValidIssuer = configuration["JwtToken:Issuer"]
66         };
67         options.Events = new JwtBearerEvents
68         {
69             OnTokenValidated = context =>
70             {
71                 context.Success();
72                 return Task.CompletedTask;
73             }
74         };
75     });
authentication

4、在请求管道中应用authentication

app.UseAuthentication();

5、添加测试controller,指定[Authorize] atrribute

 1 [Authorize]
 2         [HttpGet("all")]
 3         public IActionResult Get([FromServices] IConfiguration configuration)
 4         {
 5             return Ok(
 6                 new
 7                 {
 8                     ID = 1,
 9                     Name = "consul service",
10                     version = 1.0,
11                     serviceIP = configuration["ip"],
12                     servicePort = configuration["port"]
13                 });
14         }
test controller

通过swagger测试返回401

 

 6、swagger中authorize之后返回[Authorize] api controller,返回200

 

 

下面介绍下如何在swagger中支持authorize及api分组

 1 #region Swagger
 2 builder.Services.AddEndpointsApiExplorer();
 3 builder.Services.AddSwaggerGen(c => 
 4 {
 5     //c.IgnoreObsoleteActions();
 6     //c.TagActionsBy(api =>
 7     //{
 8     //    if (api.GroupName != null)
 9     //        return new[] { api.GroupName };
10     //    var controllerActionDescriptor = api.ActionDescriptor as ControllerActionDescriptor;
11     //    if (controllerActionDescriptor != null)
12     //        return new[] { controllerActionDescriptor.ControllerName };
13     //    throw new InvalidOperationException("Unable to determine tag for endpoint.");
14     //});
15     //c.DocInclusionPredicate((name, api) => api.GroupName == "demo1");
16 
17     c.SwaggerDoc("demo1", new OpenApiInfo { Title = "demo1", Description = "this is demo1 v1", Version = "demo1v1" });
18     c.SwaggerDoc("demo2", new OpenApiInfo { Title = "demo2", Description = "this is demo2 v1", Version = "demo2v1" });
19 
20     c.AddSecurityDefinition("bearerauth", new OpenApiSecurityScheme
21     {
22         Name = "Authorization",
23         Type = SecuritySchemeType.Http,
24         Scheme = "Bearer",
25         BearerFormat = "Bearer",
26         In = ParameterLocation.Header,
27         Description = "JWT Authorization header using the Bearer scheme."
28     });
29     c.AddSecurityRequirement(new OpenApiSecurityRequirement
30     {
31         {
32             new OpenApiSecurityScheme
33             {
34                 //Notes: this is for swagger authentication
35                 //Type= SecuritySchemeType.Http,
36                 //In= ParameterLocation.Header,
37 
38                 Reference=new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "bearerauth" }
39             },
40             new string[]{}
41         }
42     });
43 });
44 #endregion
swagger authorize & group
1 app.UseSwagger();
2 app.UseSwaggerUI(c =>
3 {
4     c.SwaggerEndpoint($"/swagger/demo1/swagger.json", "demo1");
5     c.SwaggerEndpoint($"/swagger/demo2/swagger.json", "demo2");
6 });
swagger group endpoint

接下来介绍Authorization Policy及custom policy

 1 builder.Services.AddAuthorization(options => 
 2 {
 3     var defaultPolicy = new AuthorizationPolicyBuilder();
 4     defaultPolicy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
 5     defaultPolicy.RequireAuthenticatedUser();
 6     options.DefaultPolicy = defaultPolicy.Build();
 7 
 8     options.AddPolicy("CustomScopePolicy", policy => 
 9     {
10         policy.RequireAuthenticatedUser();
11         policy.RequireClaim("Scope", "API");
12     });
13     options.AddPolicy("CustomRolePolicy", policy => 
14     {
15         policy.RequireAuthenticatedUser();
16         policy.RequireClaim("Role", "Admin");
17     });
18     options.AddPolicy("RoleScopePolicy", policy =>
19     {
20         policy.RequireAuthenticatedUser();
21         policy.AddRequirements(new CustomRequirement("admin"));
22     });
23 });
24 
25 builder.Services.AddTransient<IJwtTokenService, JwtTokenService>();
26 builder.Services.AddSingleton<IAuthorizationHandler, CustomRoleBaseAuthorizationHandler>();
27 builder.Services.AddSingleton<IAuthorizationHandler, CustomScopeBaseAuthorizationHandler>();
policy
app.UseAuthorization();
 1  public class CustomRoleBaseAuthorizationHandler : AuthorizationHandler<CustomRequirement>
 2     {
 3         protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomRequirement requirement)
 4         {
 5             var principal = context.User;
 6             var roleClaim = principal.Claims.FirstOrDefault(c => c.Type.Equals("Role", StringComparison.OrdinalIgnoreCase));
 7             if (roleClaim?.Value.Equals(requirement.Role, StringComparison.OrdinalIgnoreCase) ?? false)
 8                 context.Succeed(requirement);
 9             return Task.CompletedTask;
10         }
11     }
12 
13  public class CustomScopeBaseAuthorizationHandler : AuthorizationHandler<CustomRequirement>
14     {
15         protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomRequirement requirement)
16         {
17             var principal = context.User;
18             var claim = principal.Claims.FirstOrDefault(c => c.Type.Equals("Scope", StringComparison.OrdinalIgnoreCase));
19             if (claim?.Value.Equals("API", StringComparison.OrdinalIgnoreCase) ?? false)
20                 context.Succeed(requirement);
21             return Task.CompletedTask;
22         }
23     }
custom policy handler
1  public class CustomRequirement : IAuthorizationRequirement
2     {
3         public string Role { get; set; }
4         public CustomRequirement(string role)
5         {
6             Role = role;
7         }   
8     }
custom requirement

添加测试controller

 1 [HttpGet("v1"), Authorize(Policy = "RoleScopePolicy")]
 2         public IActionResult Index()
 3         {
 4             return new JsonResult(new List<string> { "group1", "group2" });
 5         }
 6 
 7         [HttpGet("v2"),Authorize(Policy = "CustomRolePolicy")]
 8         [ApiExplorerSettings(IgnoreApi = false)]
 9         public IActionResult IndexV2()
10         {
11             return new JsonResult(new List<string> { "group3", "group4" });
12         }
test controller

测试结果

 

 OK 搞定!

posted @ 2023-03-04 09:36  云霄宇霁  阅读(105)  评论(0编辑  收藏  举报