Categories
Uncategorized

ASP.NET Core 2.2:. Twenty-seven JWT and user authorization (refined to Action)

The last chapter how to share user authentication in ASP.NET Core Application Token JWT and refresh, proceed to the next chapter, user authorization. Examples are also related to the basis of the previous chapter. (ASP.NET Core Series Catalog)

I. Overview

First talk about certification (authentication) and authorization (authorization), they often work together, so sometimes you could not tell. And the two English words look a lot like brothers. For example, I brush into the company access cards, access control [certification] is my staff here, may enter; but later joined the company, I am not all rooms can enter, such as “the engine room powerhouse, No Admittance,” I What can enter the room, need to authorize [company]. This is the difference between authentication and authorization.

ASP.NET Core advocate is based authorization (Claim), and on this Claim, I had used the previous chapter, following such a code, but not presented:

Claim[] claims = new Claim[] { new Claim(ClaimTypes.NameIdentifier, user.Code), new Claim(ClaimTypes.Name, user.Name) };

This is a collection of a statement, which contains two declarations for saving the unique ID and user name of the user. Of course, we can also add more of Claim. Corresponding to the Claim, there are two types ClaimsIdentity and ClaimsPrincipal.

ClaimsIdentity is equivalent to a document, such as the example of access cards; ClaimsPrincipal is a document holder, that is myself; then the corresponding Claim that some of the information stored within the access cards, such as identification number, holder’s name and so on.

I addition to the access cards as well as identity cards, bank cards, etc., that is to say a ClaimsPrincipal can have multiple ClaimsIdentity, and a ClaimsIdentity can have multiple Claim. ASP.NET Core licensing model probably is one such system.

ASP.NET Core supports a variety License, including compatibility with previous authorization roles. By following a few examples to explain (to the last chapter of the code example is still based).

Second, the role-based authorization

ASP.NET Core compatible with prior authorization of role models, how to use it? Since the focus of this article is not, here is a brief talk about. Modify FlyLolo.JWT.Server of TokenHelper temporarily add a permission called “TestPutBookRole” is Joe Smith (actual source of authority here not shown).

        public ComplexToken CreateToken(User user)
        {
            Claim[] claims = new Claim[] { new Claim(ClaimTypes.NameIdentifier, user.Code), new Claim(ClaimTypes.Name, user.Name) };

            //

Next, the seating 001 is a code added to the Claim one, the Token Test for storing user character information, corresponding to the test method BookController Put in FlyLolo.JWT.API, if less than deletable

if (user.Code.Equals("001")) { claims = claims.Append(new Claim(ClaimTypes.Role, "TestPutBookRole")).ToArray(); } return CreateToken(claims); }

Modify FlyLolo.JWT.API of BookController, add an Action follows

        /// 
        /// 测试在JWT的token中添加角色,在此验证  见TokenHelper
        /// 
        /// 
        [HttpPut]
        [Authorize(Roles = "TestPutBookRole")]
        public JsonResult Put()
        {
            return new JsonResult("Put  Book ...");
        }

Visit this Action, Only Joe Smith after login acquired Token normal visit.

Third, claims-based authorization

For the above example, it is also based on the statement (Claim) authorization in nature since the seating of “TestPutBookRole” role as a Claim is also added to the certificate. But using a specific ClaimTypes.Role. Whether it be as a basis for other common Claim authorize it? Of course it is possible.

Here another word related to the “Policy”, translated into policy? That is, the set of rules (such as requiring full name is John Doe, account number 002, for the Chinese nationality, etc.) combined together to form a Policy, only to meet before they can be authorized to access this Policy.

Here we create a new Policy, add the authorization code in the Startup ConfigureServices in:

services.AddAuthorization(options=>options.AddPolicy("Name",policy=> {
   policy.RequireClaim(ClaimTypes.Name, "

Joe Smith

"); policy.RequireClaim(ClaimTypes.NameIdentifier,"001"); }));

Add Action as a BookController

[HttpDelete]
[Authorize(Policy = "TestPolicy")]
public JsonResult Delete()
{
    return new JsonResult("Delete Book ...");
}

By Joe Smith and John Doe account test, only the use of John’s account of the Token can get a successful visit.

Fourth, policy-based custom authorization

The above describes two License now have a question, authorization by the role, only suitable for small projects, several functions can be separated by the character area.

Declaratively, visually actual projects need to declare a series of Policy in Startup, and then use the Controller or the Action.

Both methods feel bad. For example, often there is a demand for: a user can have multiple roles, each API corresponding to a plurality of accessible addresses (refined to a specific authorization Action). Users can also be granted special permission to an API addresses.

This demand using the above two methods are cumbersome to implement, fortunately ASP.NET Core provides a convenient way to expand.

1. Sample Data

The above summary of what the needs of the final form of the data can be formed as follows:

/// 
/// 虚拟数据,模拟从数据库或缓存中读取用户相关的权限
/// 
public static class TemporaryData
{
    public readonly static List UserPermissions = new List {
        new UserPermissions {
            Code = "001",
            Permissions = new List {
                new Permission { Code = "A1", Name = "student.create", Url = "/api/student",Method="post" },
                new Permission { Code = "A2", Name = "student.delete", Url = "/api/student",Method="delete"}
            }
        },
        new UserPermissions {
            Code = "002",
            Permissions = new List {
                new Permission { Code = "B1", Name = "book.create", Url = "/api/book" ,Method="post"},
                new Permission { Code = "B2", Name = "book.delete", Url = "/api/book" ,Method="delete"}
            }
        },
    };

    public static UserPermissions GetUserPermission(string code)
    {
        return UserPermissions.FirstOrDefault(m => m.Code.Equals(code));
    }
}

It involves the following two classes:

    public class Permission
    {
        public string Code { get; set; }
        public string Name { get; set; }
        public string Url { get; set; }

        public string Method { get; set; }
    }

    public class UserPermissions
    {
        public string Code { get; set; }
        public List Permissions { get; set; }
    }

 

2. custom handler

Here it is to develop appropriate treatment programs, according to the sample data. This involves two IAuthorizationRequirement and AuthorizationHandler content.

IAuthorizationRequirement is an empty interface, mainly used to provide the authorization needed to meet the “requirements”, or “rule.” AuthorizationHandler is jointly process the request and “Requirements”.

Create a PermissionRequirement achieve IAuthorizationRequirement interface.

public class PermissionRequirement: IAuthorizationRequirement
{
    public List UsePermissionList { get { return TemporaryData.UserPermissions; } }
}

Very simple content. It’s “request” is a list of the user’s permissions, user permissions list contains the current API access, the authorization, or do not pass.

Analyzing logic in the newly created PermissionHandler:

public class PermissionHandler : AuthorizationHandler
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
    {
        var code = context.User.Claims.FirstOrDefault(m => m.Type.Equals(ClaimTypes.NameIdentifier));
        if (null != code)
        {
            UserPermissions userPermissions = requirement.UsePermissionList.FirstOrDefault(m => m.Code.Equals(code.Value.ToString()));

            var Request = (context.Resource as AuthorizationFilterContext).HttpContext.Request;

            if (null != userPermissions && userPermissions.Permissions.Any(m => m.Url.ToLower().Equals(Request.Path.Value.ToLower()) && m.Method.ToLower().Equals(Request.Method.ToLower()) ))
            {
                context.Succeed(requirement);
            }
            else
            {
                context.Fail();
            }
        }
        else
        {
            context.Fail();
        }

        return Task.CompletedTask;
    }
}

Simple logic is not described.

3. The use of a custom handler

Add in the Startup authorization code in the ConfigureServices

services.AddAuthorization(options => options.AddPolicy("Permission", policy => policy.Requirements.Add(new PermissionRequirement())));
services.AddSingleton();

The BookController modify the Delete Action:

[HttpDelete]
//[Authorize(Policy = "TestPolicy")]
[Authorize(Policy = "Permission")]
public JsonResult Delete()
{
    return new JsonResult("Delete Book ...");
}

Test only John Doe can access this Action.

 

Code address: https: //github.com/FlyLolo/JWT.Demo/releases/tag/2.0

Leave a Reply