Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Role based authorization with IdentityServer4

I am trying to implement "Role Based Authorization" using IdentityServer4 to give access to my API based on the user roles.

For example , I want to have two roles for the user i.e. FreeUser and PaidUser and want to give access to the API through the Authorize Attribute using [Authorize(Roles = "FreeUser"))], Kindly help me that How can I achieve this.

I have the following solution structure :

  1. IdentityServer
  2. WebApi
  3. Javascript Client

I have registered my Javascript client as follows:

 new Client             {                 ClientId = "js",                 ClientName = "javascript client",                 AllowedGrantTypes = GrantTypes.Implicit,                 AllowAccessTokensViaBrowser= true,                 RedirectUris = {"http://localhost:5004/callback.html"},                 PostLogoutRedirectUris = {"http://localhost:5004/index.html"},                 AllowedCorsOrigins = {"http://localhost:5004"},                  AllowedScopes =                 {                     StandardScopes.OpenId.Name,                     StandardScopes.Profile.Name,                     "api1",                     "role",                     StandardScopes.AllClaims.Name                 }             } 

Scopes

 return new List<Scope>         {             StandardScopes.OpenId,             StandardScopes.Profile,              new Scope             {                 Name = "api1",                 Description = "My API"             },            new Scope            {                Enabled = true,                Name  = "role",                DisplayName = "Role(s)",                Description = "roles of user",                Type = ScopeType.Identity,                Claims = new List<ScopeClaim>                {                    new ScopeClaim("role",false)                }            },            StandardScopes.AllClaims         }; 

Users

 return new List<InMemoryUser>         {             new InMemoryUser             {                 Subject = "1",                 Username = "alice",                 Password = "password",                  Claims = new List<Claim>                 {                     new Claim("name", "Alice"),                     new Claim("website", "https://alice.com"),                     new Claim("role","FreeUser")                 }             },             new InMemoryUser             {                 Subject = "2",                 Username = "bob",                 Password = "password",                  Claims = new List<Claim>                 {                     new Claim("name", "Bob"),                     new Claim("website", "https://bob.com"),                     new Claim("role","PaidUser")                 }             }         }; 

WebApi Startup.cs

  public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)     {         loggerFactory.AddConsole(Configuration.GetSection("Logging"));         loggerFactory.AddDebug();           JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();         app.UseCors("default");         app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions         {             Authority = "http://localhost:5000",             ScopeName = "api1",             //  AdditionalScopes = new List<string> { "openid","profile", "role" },             RequireHttpsMetadata = false         });          app.UseMvc();     } 

Web Api controller

namespace Api.Controllers {  [Route("[controller]")]  public class IdentityController : ControllerBase {     [HttpGet]     [Authorize(Roles = "PaidUser")]     public IActionResult Get()     {         return new JsonResult(from c in User.Claims select new { c.Type,    c.Value });     }      [Authorize(Roles = "FreeUser")]     [HttpGet]     [Route("getfree")]     public IActionResult GetFreeUser()     {         return new JsonResult(from c in User.Claims select new { c.Type, c.Value });     } } } 

Javascript Client app.js Here I am trying to login the user through IdentityServer and make an API Request.

var mgr = new Oidc.UserManager(config); mgr.getUser().then(function (user) { if (user) {     log("User logged in", user.profile); } else {     log("User is not logged in."); } });  function login() {   mgr.signinRedirect();  }  function api() { mgr.getUser().then(function (user) {     var url = "http://localhost:5001/identity/getfree";      var xhr = new XMLHttpRequest();     xhr.open("GET", url);     xhr.onload = function () {         log(xhr.status, JSON.parse(xhr.responseText));     };      xhr.setRequestHeader("Authorization", "Bearer " + user.access_token);     xhr.send();   });  }   function logout() {    mgr.signoutRedirect();  } 

The Login flow works fine and I can login successfully, and I can receive the role in the access token.

enter image description here

When I make a request to the API by clicking the button (Call Api) then I get the following error.. enter image description here

like image 696
muhammad waqas Avatar asked Nov 28 '16 12:11

muhammad waqas


People also ask

Is IdentityServer4 obsolete?

IdentityServer4 support will last until the end of life of . NET Core 3.1 that means till November 2022. In that way, Duende provides new documentation for the fifth service version.

How does role based authorization work?

Role-based authorization checks specify which roles which the current user must be a member of to access the requested resource. The controller SalaryController is only accessible by users who are members of the HRManager role or the Finance role.

What is the use of IdentityServer4?

IdentityServer is an authentication server that implements OpenID Connect (OIDC) and OAuth 2.0 standards for ASP.NET Core. It's designed to provide a common way to authenticate requests to all of your applications, whether they're web, native, mobile, or API endpoints.


Video Answer


2 Answers

Given that you have not provided config object for javascript client, I assume you have scope configured as follows.

scope:"openid profile api1 role" 

I believe that the main reason for your issue is that role claim is not included in your access token.

Add role claim to api1 scope as follows to include it in the access token.

             new Scope                 {                     Name = "api1",                     DisplayName = "API1 access",                     Description = "My API",                     Type = ScopeType.Resource,                     IncludeAllClaimsForUser = true,                     Claims = new List<ScopeClaim>                     {                         new ScopeClaim(ClaimTypes.Name),                         new ScopeClaim(ClaimTypes.Role)                     }                 } 

You can read my answer here for help debug the issue. implementing roles in identity server 4 with asp.net identity

The complete working solution is here. https://github.com/weliwita/IdentityServer4.Samples/tree/40844310

like image 175
rawel Avatar answered Sep 21 '22 12:09

rawel


Change new Claim("role","FreeUser") to new Claim(ClaimTypes.Role, "FreeUser")

Or create a policy like this:

services.AddAuthorization(options => {     options.AddPolicy("FreeUser", policy => policy.RequireClaim("role", "FreeUser")); }); 

and use it :

[Authorize(Policy = "FreeUser")] 
like image 44
adem caglin Avatar answered Sep 21 '22 12:09

adem caglin