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 :
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.
When I make a request to the API by clicking the button (Call Api) then I get the following error..
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.
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.
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.
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
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")]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With