zoukankan      html  css  js  c++  java
  • ASP.NET Web API Claims Authorization with ASP.NET Identity 2.1 Part 5 (by TAISEER)

    https://www.cnblogs.com/KimmyLee/p/6430474.html

    https://www.cnblogs.com/rocketRobin/p/9077523.html

    http://bitoftech.net/2015/03/31/asp-net-web-api-claims-authorization-with-asp-net-identity-2-1/

    ASP.NET Web API Claims Authorization with ASP.NET Identity 2.1

    In the previous post we have implemented a finer grained way to control authorization based on the Roles assigned for the authenticated user, this was done by assigning users to a predefined Roles in our system and then attributing the protected controllers or actions by the [Authorize(Roles = “Role(s) Name”)]attribute.

    Using Roles Based Authorization for controlling user access will be efficient in scenarios where your Roles do not change too much and the users permissions do not change frequently.

    In some applications controlling user access on system resources is more complicated, and having users assigned to certain Roles is not enough for managing user access efficiently, you need more dynamic way to to control access based on certain information related to the authenticated user, this will lead us to control user access using Claims, or in another word using Claims Based Authorization.

    But before we dig into the implementation of Claims Based Authorization we need to understand what Claims are!

    Note: It is not mandatory to use Claims for controlling user access, if you are happy with Roles Based Authorization and you have limited number of Roles then you can stick to this.

    What is a Claim?

    Claim is a statement about the user makes about itself, it can be user name, first name, last name, gender, phone, the roles user assigned to, etc… Yes the Roles we have been looking at are transformed to Claims at the end, and as we saw in the previous post; in ASP.NET Identity those Roles have their own manager (ApplicationRoleManager) and set of APIs to manage them, yet you can consider them as a Claim of type Role.

    As we saw before, any authenticated user will receive a JSON Web Token (JWT) which contains a set of claims inside it, what we’ll do now is to create a helper end point which returns the claims encoded in the JWT for an authenticated user.

    To do this we will create a new controller named “ClaimsController” which will contain a single method responsible to unpack the claims in the JWT and return them, to do this add new controller named “ClaimsController” under folder Controllers and paste the code below:

    [RoutePrefix("api/claims")]
        public class ClaimsController : BaseApiController
        {
            [Authorize]
            [Route("")]
            public IHttpActionResult GetClaims()
            {
                var identity = User.Identity as ClaimsIdentity;
                
                var claims = from c in identity.Claims
                             select new
                             {
                                 subject = c.Subject.Name,
                                 type = c.Type,
                                 value = c.Value
                             };
     
                return Ok(claims);
            }
     
        }

    The code we have implemented above is straight forward, we are getting the Identity of the authenticated user by calling “User.Identity” which returns “ClaimsIdentity” object, then we are iterating over the IEnumerable Claims property and return three properties which they are (Subject, Type, and Value).
    To execute this endpoint we need to issue HTTP GET request to the end point “http://localhost/api/claims” and do not forget to pass a valid JWT in the Authorization header, the response for this end point will contain the below JSON object:

    [

      {
        "subject": "Hamza",
        "type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
        "value": "cd93945e-fe2c-49c1-b2bb-138a2dd52928"
      },
      {
        "subject": "Hamza",
        "type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
        "value": "Hamza"
      },
      {
        "subject": "Hamza",
        "type": "http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider",
        "value": "ASP.NET Identity"
      },
      {
        "subject": "Hamza",
        "type": "AspNet.Identity.SecurityStamp",
        "value": "a77594e2-ffa0-41bd-a048-7398c01c8948"
      },
      {
        "subject": "Hamza",
        "type": "iss",
        "value": "http://localhost:59822"
      },
      {
        "subject": "Hamza",
        "type": "aud",
        "value": "414e1927a3884f68abc79f7283837fd1"
      },
      {
        "subject": "Hamza",
        "type": "exp",
        "value": "1427744352"
      },
      {
        "subject": "Hamza",
        "type": "nbf",
        "value": "1427657952"
      }
    ]

    As you noticed from the response above, all the claims contain three properties, and those properties represents the below:

    • Subject: Represents the identity which those claims belongs to, usually the value for the subject will contain the unique identifier for the user in the system (Username or Email).
    • Type: Represents the type of the information contained in the claim.
    • Value: Represents the claim value (information) about this claim.

    Now to have better understanding of what type of those claims mean let’s take a look the table below:

    After we have briefly described what claims are, we want to see how we can use them to manage user assess, in this post I will demonstrate three ways of using the claims as the below:

    1. Assigning claims to the user on the fly based on user information.
    2. Creating custom Claims Authorization attribute.
    3. Managing user claims by using the “ApplicationUserManager” APIs.

    Method 1: Assigning claims to the user on the fly

    Method 2: Creating custom Claims Authorization attribute

    Method 3: Managing user claims by using the “ApplicationUserManager” APIs

    The last method we want to explore here is to use the “ApplicationUserManager” claims related API to manage user claims and store them in ASP.NET Identity related tables “AspNetUserClaims”.

    In the previous two methods we’ve created claims for the user on the fly, but in method 3 we will see how we can add/remove claims for a certain user.

    The “ApplicationUserManager” class comes with a set of predefined APIs which makes dealing and managing claims simple, the APIs that we’ll use in this post are listed in the table below:

    To use those APIs let’s add 2 new methods to the “AccountsController”, the first method “AssignClaimsToUser” will be responsible to add new claims for specified user, and the second method “RemoveClaimsFromUser” will remove claims from a specified user as the code below:

    [Authorize(Roles = "Admin")]
    [Route("user/{id:guid}/assignclaims")]
    [HttpPut]
    public async Task<IHttpActionResult> AssignClaimsToUser([FromUri] string id, [FromBody] List<ClaimBindingModel> claimsToAssign) {
     
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
     
         var appUser = await this.AppUserManager.FindByIdAsync(id);
     
        if (appUser == null)
        {
            return NotFound();
        }
     
        foreach (ClaimBindingModel claimModel in claimsToAssign)
        {
            if (appUser.Claims.Any(c => c.ClaimType == claimModel.Type)) {
               
                await this.AppUserManager.RemoveClaimAsync(id, ExtendedClaimsProvider.CreateClaim(claimModel.Type, claimModel.Value));
            }
     
            await this.AppUserManager.AddClaimAsync(id, ExtendedClaimsProvider.CreateClaim(claimModel.Type, claimModel.Value));
        }
        
        return Ok();
    }
     
    [Authorize(Roles = "Admin")]
    [Route("user/{id:guid}/removeclaims")]
    [HttpPut]
    public async Task<IHttpActionResult> RemoveClaimsFromUser([FromUri] string id, [FromBody] List<ClaimBindingModel> claimsToRemove)
    {
     
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
     
        var appUser = await this.AppUserManager.FindByIdAsync(id);
     
        if (appUser == null)
        {
            return NotFound();
        }
     
        foreach (ClaimBindingModel claimModel in claimsToRemove)
        {
            if (appUser.Claims.Any(c => c.ClaimType == claimModel.Type))
            {
                await this.AppUserManager.RemoveClaimAsync(id, ExtendedClaimsProvider.CreateClaim(claimModel.Type, claimModel.Value));
            }
        }
     
        return Ok();
    }

    The implementation for both methods is very identical, as you noticed we are only allowing users in “Admin” role to access those endpoints, then we are specifying the UserId and a list of the claims that will be add or removed for this user.

    Then we are making sure that user specified exists in our system before trying to do any operation on the user.

    In case we are adding a new claim for the user, we will check if the user has the same claim type before trying to add it, add if it exists before we’ll remove this claim and add it again with the new claim value.

    The same applies when we try to remove a claim from the user, notice that methods “AddClaimAsync” and “RemoveClaimAsync” will save the claims permanently in our SQL data-store in table “AspNetUserClaims”.

    Do not forget to add the “ClaimBindingModel” under folder “Models” which acts as our POCO class when we are sending the claims from our front-end application, the class will contain the code below:

    public class ClaimBindingModel
        {
            [Required]
            [Display(Name = "Claim Type")]
            public string Type { get; set; }
     
            [Required]
            [Display(Name = "Claim Value")]
            public string Value { get; set; }
        }

    There is no extra steps needed in order to pull those claims from the SQL data-store when establishing the user identity, thanks for the method “CreateIdentityAsync” which is responsible to pull all the claims for the user. We have already implemented this and it can be checked by visiting the highlighted LOC.

    To test those methods all you need to do is to issue HTTP PUT request to the URI: “http://localhost:59822/api/accounts/user/{UserId}/assignclaims” and “http://localhost:59822/api/accounts/user/{UserId}/removeclaims” as the request images below:

    That’s it for now folks about implementing Authorization using Claims.

  • 相关阅读:
    打成jar包运行,依然可以找到指定路径的xml
    Springboot整合Ehcache 解决Mybatis二级缓存数据脏读 -详细
    Handler dispatch failed; nested exception is java.lang.NoClassDefFoundError: org/dom4j/io/SAXReader
    Springboot + Mybatis + Ehcache
    Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured. Reason: Failed to determine a suitable driver class
    缓存的设计与使用
    一二级缓存
    HttpServletResponse 返回的json数据不是json字符串,而是json对象
    消息中间件选型
    为什么要使用MQ消息中间件?
  • 原文地址:https://www.cnblogs.com/chucklu/p/10346702.html
Copyright © 2011-2022 走看看