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:
SUBJECT | TYPE | VALUE | NOTES |
---|---|---|---|
Hamza | nameidentifier | cd93945e-fe2c-49c1-b2bb-138a2dd52928 | Unique User Id generated from Identity System |
Hamza | name | Hamza | Unique Username |
Hamza | identityprovider | ASP.NET Identity | How user has been authenticated using ASP.NET Identity |
Hamza | SecurityStamp | a77594e2-ffa0-41bd-a048-7398c01c8948 | Unique Id which stays the same until any security related attribute change, i.e. change user password |
Hamza | iss | http://localhost:59822 | Issuer of the Access Token (Authz Server) |
Hamza | aud | 414e1927a3884f68abc79f7283837fd1 | For which system this token is generated |
Hamza | exp | 1427744352 | Expiry time for this access token (Epoch) |
Hamza | nbf | 1427657952 | When this token is issued (Epoch) |
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:
- Assigning claims to the user on the fly based on user information.
- Creating custom Claims Authorization attribute.
- 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:
METHOD NAME | USAGE |
---|---|
AddClaimAsync(id, claim) | Create a new claim for specified user id |
RemoveClaimAsync(id, claim) | Remove claim from specified user if claim type and value match |
GetClaimsAsync(id) | Return IEnumerable of claims based on specified user id |
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.
ASP.NET Web API Claims Authorization with ASP.NET Identity 2.1 Part 5 (by TAISEER)的更多相关文章
- 【ASP.NET Web API教程】1 ASP.NET Web API入门
原文 [ASP.NET Web API教程]1 ASP.NET Web API入门 Getting Started with ASP.NET Web API第1章 ASP.NET Web API入门 ...
- Announcing the Release of ASP.NET MVC 5.1, ASP.NET Web API 2.1 and ASP.NET Web Pages 3.1 for VS2012
The NuGet packages for ASP.NET MVC 5.1, ASP.NET Web API 2.1 and ASP.NET Web Pages 3.1 are now live o ...
- Implement JSON Web Tokens Authentication in ASP.NET Web API and Identity 2.1 Part 3 (by TAISEER)
http://bitoftech.net/2015/02/16/implement-oauth-json-web-tokens-authentication-in-asp-net-web-api-an ...
- 杂项:ASP.NET Web API
ylbtech-杂项:ASP.NET Web API ASP.NET Web API 是一种框架,用于轻松构建可以访问多种客户端(包括浏览器和移动设备)的 HTTP 服务. ASP.NET Web A ...
- ASP.NET Web API 控制器执行过程(一)
ASP.NET Web API 控制器执行过程(一) 前言 前面两篇讲解了控制器的创建过程,只是从框架源码的角度去简单的了解,在控制器创建过后所执行的过程也是尤为重要的,本篇就来简单的说明一下控制器在 ...
- ASP.NET Web API WebHost宿主环境中管道、路由
ASP.NET Web API WebHost宿主环境中管道.路由 前言 上篇中说到ASP.NET Web API框架在SelfHost环境中管道.路由的一个形态,本篇就来说明一下在WebHost环境 ...
- ASP.NET Web API Selfhost宿主环境中管道、路由
ASP.NET Web API Selfhost宿主环境中管道.路由 前言 前面的几个篇幅对Web API中的路由和管道进行了简单的介绍并没有详细的去说明一些什么,然而ASP.NET Web API这 ...
- ASP.NET Web API 管道模型
ASP.NET Web API 管道模型 前言 ASP.NET Web API是一个独立的框架,也有着自己的一套消息处理管道,不管是在WebHost宿主环境还是在SelfHost宿主环境请求和响应都是 ...
- ASP.NET Web API 路由对象介绍
ASP.NET Web API 路由对象介绍 前言 在ASP.NET.ASP.NET MVC和ASP.NET Web API这些框架中都会发现有路由的身影,它们的原理都差不多,只不过在不同的环境下作了 ...
随机推荐
- Incompatible integer to pointer conversion assigning to 'NSInteger *' (aka 'int *') from 'NSInteger' (aka 'int')
遇到这样的问题: integer to pointer conversion assigning to 'NSInteger *' (aka 'int *') from 'NSInteger' (ak ...
- Put queue for MemoryTransaction of capacity 10000 full, consider committing more frequently, increasing capacity or increasing thread count flume capacity 时间数
package com.test; import org.apache.http.*;import org.apache.http.entity.ContentType;import org.apac ...
- ctf-HITCON-2016-houseoforange学习
目录 堆溢出点 利用步骤 创建第一个house,修改top_chunk的size 创建第二个house,触发sysmalloc中的_int_free 创建第三个house,泄露libc和heap的地址 ...
- 转:java高并发学习记录-死锁,活锁,饥饿
死锁 两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去. 为什么会产生死锁: ① 因为系统资源不足. ② 进程运行推进的顺序不合适. ③ ...
- 一个误区(关于javascript的字符串拼接)
前段时间听说了一个问题,说是,javascript中使用+=来拼接字符串会比使用Array的join方法慢几十倍以上,今天在工作间歇,就写了个例 子验证了一下,结果确完全相反,使用+=比join要快( ...
- Windows常见宏的使用
WIN32_LEAN_AND_MEAN 1. 参考资料:https://msdn.microsoft.com/en-us/library/windows/desktop/aa383745(v=vs. ...
- Outputting Strings in the Console
Outputting Strings in the Console #include <windows.h> class Console {public: enum fore_color ...
- knockout 学习使用笔记----绑定map--双向绑定
简单的方式,使用 knockout.mapping.js. 1.引入knockout.mapping.js. 2.声明模型 var model = { task:null, feedbacks:[], ...
- IISExpress 站点信息
目录:C:\Users\huxl16\Documents\IISExpress\config applicationhost:applicationhost.config
- Codeforces Round #403 (Div. 2, based on Technocup 2017 Finals) E Underground Lab
地址:http://codeforces.com/contest/782/problem/E 题目: E. Underground Lab time limit per test 1 second m ...