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

 

 


Log in, To getToken, And then every timeHeader Secondary additionAuthorization byToken Credentials, If the server passes the verification, it is possible to obtain the resources it wants to access. aboutJWT Technology, Please refer to the articles on the Internet, No details here,

This blog post, Main description inasp.net core 2.0 in, Be based onjwt Ofweb api Permission settings for, That is, inasp.net
core How to use itJWT, Again, different users or roles have different permissions, Even if invokedToken, 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. stayStartup OfConfigureServices Injection validation(Authentication), To grant authorization(Authorization), andJWT(JwtBearer)

Custom policy:

Has been closed intoAuthorizeRolicy.JWT nuget package, And publish tonuget upper:

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

Source code is as follows:

JwtToken.cs
/// <summary> /// Get based onJWT OfToken /// </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> /// requestUrl /// </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 authorityaction 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 ///
Publisher32 /// </summary> 33 public string Issuer { get; set; } 34 /// <summary> 35
/// Subscribers 36 /// </summary> 37 public string Audience { get; set; } 38 ///
<summary> 39 /// Expiration date 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 authorityaction</param> 51 /// <param
name="userPermissions"> User rights collection</param> 52 53 /// <summary> 54 /// structure 55 ///
</summary> 56 /// <param name="deniedAction"> Repudiatedurl</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 classPermissionHandler.cs
/// <summary> /// Authority authorizationHandler /// </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;
// fromAuthorizationHandlerContext Turn intoHttpContext, So as to take out the table for information var httpContext =
(context.Resource as
Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext).HttpContext;
// requestUrl 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 requestedurl 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; // Authentication authority 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 loginurl, And isPost request, And help isform 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 buildasp.net core 2.0 Ofweb api project, And addAuthorizePolicy.JWT Pictured



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

  "Audience": {

    "Secret": "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",

    "Issuer": "gsw",

    "Audience": "everone"

  }

stayConfigureServices Middle injection verification(Authentication), To grant authorization(Authorization), andJWT(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, yesClaimTypes.Role, For each element of the above collectionName Is the role name, IfClaimTypes.Name, That is, theName Username
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 upToken Expiration date42 ); 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 //
No usehttps 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 authorizationHandler 72
services.AddSingleton<IAuthorizationHandler, PermissionHandler>(); 73
services.AddSingleton(permissionRequirement);74 services.AddMvc(); 75 }
 

In need of teachingController 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 correctToken, If fail, Validation failed, Another unauthorized navigation after successful loginaction.
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, useRestSharp To access our definedweb
api, among1 byadmin Role logged in,2 bysystem Role logged in,3 Login for wrong user password,4 Is a query function, staystartup.cs in,admin Role has query/api/values Permissions, So useadmin Login can be accessed normally, usesystem 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> /// VisitUrl /// </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 byBearer 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 result:{content}"); } }
  

Operation result:



 

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