JWT(json web token) It's based on json Authentication mechanism of , The process is as follows :

 

 


By logging in , To get Token, And then every time Header Middle append Authorization by Token Credentials for , If the server passes the verification, it is possible to obtain the resources it wants to access . about JWT Technology of , Please refer to the articles on the Internet , No details here ,

This post , Main description in asp.net core 2.0 in , be based on jwt Of web api Permission settings for , I.e asp.net
core How to use it JWT, Again, different users or roles have different permissions , Even if you call Token, You can't access resources that you shouldn't .


The basic idea is that we define a strategy , To verify users , And verify user authorization ,PermissionRequirement Is a parameter for verifying transmission authorization . stay Startup Of ConfigureServices Injection verification (Authentication), to grant authorization (Authorization), and JWT(JwtBearer)

Custom policy :

Closed as AuthorizeRolicy.JWT nuget package , And publish to nuget upper :

https://www.nuget.org/packages/AuthorizePolicy.JWT/
<https://www.nuget.org/packages/AuthorizePolicy.JWT/>

The source code is as follows :

JwtToken.cs
/// <summary> /// Get based on JWT Of Token /// </summary> /// <param
name="username"></param> /// <returns></returns> public static dynamic
BuildJwtToken(Claim[] claims, PermissionRequirement permissionRequirement) {
var now = DateTime.UtcNow; var jwt = new JwtSecurityToken( issuer:
permissionRequirement.Issuer, audience: permissionRequirement.Audience, claims:
claims, notBefore: now, expires: now.Add(permissionRequirement.Expiration),
signingCredentials: permissionRequirement.SigningCredentials ); var encodedJwt
= new JwtSecurityTokenHandler().WriteToken(jwt); var response = new { Status =
true, access_token = encodedJwt, expires_in =
permissionRequirement.Expiration.TotalMilliseconds, token_type = "Bearer" };
return response; }
  

Permission.cs
/// <summary> /// User or role or other credential entity /// </summary> public class Permission { ///
<summary> /// User or role or other credential name /// </summary> public virtual string Name { get;
set; } /// <summary> /// request Url /// </summary> public virtual string Url { get;
set; } }
  PermissionRequirement.cs
1 using Microsoft.AspNetCore.Authorization; 2 using
Microsoft.IdentityModel.Tokens; 3 using System; 4 using
System.Collections.Generic; 5 6 namespace AuthorizePolicy.JWT 7 { 8 ///
<summary> 9 /// Necessary parameter class 10 /// </summary> 11 public class PermissionRequirement
: IAuthorizationRequirement12 { 13 /// <summary> 14 /// User rights collection 15 ///
</summary> 16 public List<Permission> Permissions { get; private set; } 17 ///
<summary> 18 /// No permission action 19 /// </summary> 20 public string DeniedAction { get
;set; } 21 22 /// <summary> 23 /// Authentication authorization type 24 /// </summary> 25 public string
ClaimType {internal get; set; } 26 /// <summary> 27 /// Request path 28 /// </summary>
29 public string LoginPath { get; set; } = "/Api/Login"; 30 /// <summary> 31 ///
publisher 32 /// </summary> 33 public string Issuer { get; set; } 34 /// <summary> 35
/// Subscribers 36 /// </summary> 37 public string Audience { get; set; } 38 ///
<summary> 39 /// Expiration time 40 /// </summary> 41 public TimeSpan Expiration { get; set
; }42 /// <summary> 43 /// Signature verification 44 /// </summary> 45 public SigningCredentials
SigningCredentials {get; set; } 46 47 /// <summary> 48 /// structure 49 /// </summary>
50 /// <param name="deniedAction"> No permission action</param> 51 /// <param
name="userPermissions"> User rights collection </param> 52 53 /// <summary> 54 /// structure 55 ///
</summary> 56 /// <param name="deniedAction"> Repudiated url</param> 57 /// <param
name="permissions"> Permission set </param> 58 /// <param name="claimType"> Declaration type </param> 59
/// <param name="issuer"> publisher </param> 60 /// <param name="audience"> Subscribers </param>
61 /// <param name="signingCredentials"> Signature verification entity </param> 62 public
PermissionRequirement(string deniedAction, List<Permission> permissions, string
claimType,string issuer, string audience, SigningCredentials
signingCredentials, TimeSpan expiration)63 { 64 ClaimType = claimType; 65
DeniedAction = deniedAction; 66 Permissions = permissions; 67 Issuer = issuer;
68 Audience = audience; 69 Expiration = expiration; 70 SigningCredentials =
signingCredentials;71 } 72 } 73 }
  Custom policy class PermissionHandler.cs
/// <summary> /// Authority authorization Handler /// </summary> public class PermissionHandler :
AuthorizationHandler<PermissionRequirement> { /// <summary> /// Validation scheme provided by ///
</summary> public IAuthenticationSchemeProvider Schemes { get; set; } ///
<summary> /// Custom policy parameters /// </summary> public PermissionRequirement Requirement {
get; set; } /// <summary> /// structure /// </summary> /// <param
name="schemes"></param> public PermissionHandler(IAuthenticationSchemeProvider
schemes) { Schemes = schemes; } protected override async Task
HandleRequirementAsync(AuthorizationHandlerContext context,
PermissionRequirement requirement) { //// Assign user rights Requirement = requirement;
// from AuthorizationHandlerContext Turn into HttpContext, So as to take out the table for information var httpContext =
(context.Resource as
Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext).HttpContext;
// request Url var questUrl = httpContext.Request.Path.Value.ToLower(); // Judge whether the request is stopped var
handlers =
httpContext.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync()) { var
handler = await handlers.GetHandlerAsync(httpContext, scheme.Name) as
IAuthenticationRequestHandler; if (handler != null && await
handler.HandleRequestAsync()) { context.Fail(); return; } } // Determine whether the request has credentials , Is there any login
var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync(); if
(defaultAuthenticate != null) { var result = await
httpContext.AuthenticateAsync(defaultAuthenticate.Name);
//result?.Principal Login success if not empty if (result?.Principal != null) { httpContext.User =
result.Principal; // Whether the requested url if (Requirement.Permissions.GroupBy(g =>
g.Url).Where(w => w.Key.ToLower() == questUrl).Count() > 0) { var name =
httpContext.User.Claims.SingleOrDefault(s => s.Type ==
requirement.ClaimType).Value; // Verify permissions if (Requirement.Permissions.Where(w =>
w.Name == name && w.Url.ToLower() == questUrl).Count() <= 0) { // No permission to jump to reject page
httpContext.Response.Redirect(requirement.DeniedAction); } }
// Judge expiration time

if (DateTime.Parse(httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Expiration).Value) >= DateTime.Now)
{
     context.Succeed(requirement);
}
else
{      context.Fail(); }
return;
}
} // When it is judged that there is no login , Whether to access the login url, And it's Post request , And help form Form submission type , Otherwise, it is a failure
if (!questUrl.Equals(Requirement.LoginPath.ToLower(),
StringComparison.Ordinal) && (!httpContext.Request.Method.Equals("POST") ||
!httpContext.Request.HasFormContentType))
{
context.Fail();
return;
}
context.Succeed(requirement);
}
}
  

newly build asp.net core 2.0 Of web api project , And add AuthorizePolicy.JWT As shown in the figure



Set profile first , The user can define the key and the user , Subscribers

  "Audience": {

    "Secret": "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",

    "Issuer": "gsw",

    "Audience": "everone"

  }

stay ConfigureServices Middle injection verification (Authentication), to grant authorization (Authorization), and JWT(JwtBearer)

Startup.cs
1 public void ConfigureServices(IServiceCollection services) 2 { 3 var
urls ="http://localhost:39287/"; 4 services.AddCors(options => 5
options.AddPolicy("MyDomain", 6 builder =>
builder.WithOrigins(urls).AllowAnyMethod().AllowAnyHeader().AllowAnyOrigin().AllowCredentials()));
7 8 // Read profile 9 var audienceConfig = Configuration.GetSection("Audience"); 10
var symmetricKeyAsBase64 = audienceConfig["Secret"]; 11 var keyByteArray =
Encoding.ASCII.GetBytes(symmetricKeyAsBase64);12 var signingKey = new
SymmetricSecurityKey(keyByteArray);13 var tokenValidationParameters = new
TokenValidationParameters14 { 15 ValidateIssuerSigningKey = true, 16
IssuerSigningKey = signingKey, 17 ValidateIssuer = true, 18 ValidIssuer =
audienceConfig["Issuer"],// publisher 19 ValidateAudience = true, 20 ValidAudience =
audienceConfig["Audience"],// Subscribers 21 ValidateLifetime = true, 22 ClockSkew =
TimeSpan.Zero,23 RequireExpirationTime = true, 24 25 }; 26 var
signingCredentials =new SigningCredentials(signingKey,
SecurityAlgorithms.HmacSha256);27 // This collection simulates the user permission table , Can be queried from the database 28 var permission =
new List<Permission> { 29 new Permission { Url="/", Name="admin"}, 30 new
Permission { Url="/api/values", Name="admin"}, 31 new Permission { Url="/",
Name="system"}, 32 new Permission { Url="/api/values1", Name="system"} 33 }; 34
//
If the third parameter , yes ClaimTypes.Role, For each element of the above collection Name Is the role name , If ClaimTypes.Name, That is, the Name Is the user name
35 var permissionRequirement = new PermissionRequirement( 36 "/api/denied",
permission,37 ClaimTypes.Role, 38 audienceConfig["Issuer"], 39 audienceConfig["
Audience"], 40 signingCredentials, 41 expiration: TimeSpan.FromSeconds(10
)// set up Token Expiration time 42 ); 43 services.AddAuthorization(options => 44 { 45 46
options.AddPolicy("Permission", 47 policy =>
policy.Requirements.Add(permissionRequirement));48 49
}).AddAuthentication(options =>50 { 51 options.DefaultAuthenticateScheme =
JwtBearerDefaults.AuthenticationScheme;52 options.DefaultChallengeScheme =
JwtBearerDefaults.AuthenticationScheme;53 }) 54 .AddJwtBearer(o => 55 { 56 //
Not used https 57 o.RequireHttpsMetadata = false; 58 o.TokenValidationParameters =
tokenValidationParameters;59 o.Events = new JwtBearerEvents 60 { 61
OnTokenValidated = context =>62 { 63 if (context.Request.Path.Value.ToString()
=="/api/logout") 64 { 65 var token = ((context as
TokenValidatedContext).SecurityTokenas JwtSecurityToken).RawData; 66 } 67
return Task.CompletedTask; 68 } 69 }; 70 }); 71 // Injection authorization Handler 72
services.AddSingleton<IAuthorizationHandler, PermissionHandler>(); 73
services.AddSingleton(permissionRequirement);74 services.AddMvc(); 75 }
 

In need of teaching Controller Add authorization feature on

    [Authorize("Permission")]

 


PermissionController Class has two methods , One is login , Verify that the user name and password are correct , Issue if correct Token, If it fails , Validation failed , Another unauthorized navigation after successful login action.
1 [Authorize("Permission")] 2 [EnableCors("MyDomain")] 3 public class
PermissionController : Controller 4 { 5 /// <summary> 6 /// Custom policy parameters 7 ///
</summary> 8 PermissionRequirement _requirement; 9 public
PermissionController(PermissionRequirement requirement)10 { 11 _requirement =
requirement;12 } 13 [AllowAnonymous] 14 [HttpPost("/api/login")] 15 public
IActionResult Login(string username, string password, string role) 16 { 17 var
isValidated = username =="gsw" && password == "111111"; 18 if (!isValidated) 19
{20 return new JsonResult(new 21 { 22 Status = false, 23 Message = " Authentication failed " 24
});25 } 26 else 27 { 28 // If it is a user based authorization policy , To add users here ; If it is role-based authorization policy , To add a role here 29 var
claims =new Claim[] { new Claim(ClaimTypes.Name, username), new
Claim(ClaimTypes.Role, role),new Claim(ClaimTypes.Expiration
,DateTime.Now.AddSeconds(_requirement.Expiration.TotalSeconds).ToString())};30
// User ID 31 var identity = new
ClaimsIdentity(JwtBearerDefaults.AuthenticationScheme);32
identity.AddClaims(claims);33 34 var token = JwtToken.BuildJwtToken(claims,
_requirement);35 return new JsonResult(token); 36 } 37 } 38 39 [HttpPost("
/api/logout")] 40 public IActionResult Logout() 41 { 42 return Ok(); 43 } 44
45 [AllowAnonymous] 46 [HttpGet("/api/denied")] 47 public IActionResult
Denied()48 { 49 return new JsonResult(new 50 { 51 Status = false, 52 Message =
" You have no access " 53 }); 54 } 55 }
 

Here's a console (.NetFramewrok) program , use RestSharp To access our defined web
api, among 1 by admin Role login ,2 by system Role login ,3 Login for wrong user password ,4 Is a query function , stay startup.cs in ,admin Role has query /api/values Of , So use admin Login can be accessed normally , use system Sign in , Can log in successfully , But no access /api/values, Wrong user name and password , visit /aip/values, It's not authorized directly
class Program { /// <summary> /// visit Url /// </summary> static string _url =
"http://localhost:39286"; static void Main(string[] args) { dynamic token =
null; while (true) { Console.WriteLine("1, Sign in 【admin】 2, Sign in 【system】 3, Sign in 【 Wrong username password 】
4, Query data "); var mark = Console.ReadLine(); var stopwatch = new Stopwatch();
stopwatch.Start(); switch (mark) { case "1": token = AdminLogin(); break; case
"2": token = SystemLogin(); break; case "3": token = NullLogin(); break; case
"4": AdminInvock(token); break; } stopwatch.Stop(); TimeSpan timespan =
stopwatch.Elapsed; Console.WriteLine($" Interval time :{timespan.TotalSeconds}"); } }
static dynamic NullLogin() { var loginClient = new RestClient(_url); var
loginRequest = new RestRequest("/api/login", Method.POST);
loginRequest.AddParameter("username", "gswaa");
loginRequest.AddParameter("password", "111111"); // Or query corresponding roles with user name and password
loginRequest.AddParameter("role", "system"); IRestResponse loginResponse =
loginClient.Execute(loginRequest); var loginContent = loginResponse.Content;
Console.WriteLine(loginContent); return
Newtonsoft.Json.JsonConvert.DeserializeObject(loginContent); } static dynamic
SystemLogin() { var loginClient = new RestClient(_url); var loginRequest = new
RestRequest("/api/login", Method.POST); loginRequest.AddParameter("username",
"gsw"); loginRequest.AddParameter("password", "111111"); // Or query corresponding roles with user name and password
loginRequest.AddParameter("role", "system"); IRestResponse loginResponse =
loginClient.Execute(loginRequest); var loginContent = loginResponse.Content;
Console.WriteLine(loginContent); return
Newtonsoft.Json.JsonConvert.DeserializeObject(loginContent); } static dynamic
AdminLogin() { var loginClient = new RestClient(_url); var loginRequest = new
RestRequest("/api/login", Method.POST); loginRequest.AddParameter("username",
"gsw"); loginRequest.AddParameter("password", "111111"); // Or query corresponding roles with user name and password
loginRequest.AddParameter("role", "admin"); IRestResponse loginResponse =
loginClient.Execute(loginRequest); var loginContent = loginResponse.Content;
Console.WriteLine(loginContent); return
Newtonsoft.Json.JsonConvert.DeserializeObject(loginContent); } static void
AdminInvock(dynamic token) { var client = new RestClient(_url);
// Here, the token string to be obtained is preceded by Bearer string tk = "Bearer " +
Convert.ToString(token?.access_token); client.AddDefaultHeader("Authorization",
tk); var request = new RestRequest("/api/values", Method.GET); IRestResponse
response = client.Execute(request); var content = response.Content;
Console.WriteLine($" state :{response.StatusCode} Return results :{content}"); } }
  

Operation results :



 

Source code :https://github.com/axzxs2001/AuthorizePolicy.JWT