2016-11-28 129 views
8

我正在尝试使用IdentityServer4实现“基于角色的授权”,以便根据用户角色授予我的API访问权限。IdentityServer4基于角色的授权

例如,我希望为用户提供两个角色,即FreeUser和PaidUser,并希望通过授权属性使用[Authorize(Roles =“FreeUser”))]访问API,请帮助我如何我可以做到这一点吗?

我有以下解决方案结构:

  1. IdentityServer
  2. 的WebAPI
  3. JavaScript客户端

我已经注册了我的JavaScript客户端如下:

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 
       } 
      } 

个作用域

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 
     }; 

用户

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(); 
    } 

网络API控制器

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客户端app.js 在这里,我试图登录通过IdentityServer用户,使API请求。

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(); 
} 

登录流程正常,我可以成功登录,并且我可以接收访问令牌中的角色。

enter image description here

当我做对API的请求通过单击按钮(呼叫API)然后我收到以下错误.. enter image description here

回答

5

鉴于您没有提供JavaScript客户端的配置对象,我假设您的作用域配置如下。

scope:"openid profile api1 role" 

我相信您的问题的主要原因是您的访问令牌中没有包含角色声明。

将角色声明添加到api1范围,如下所示将其包含在访问令牌中。

   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) 
        } 
       } 

你可以在这里阅读我的答案以帮助调试问题。 implementing roles in identity server 4 with asp.net identity

完整的工作解决方案就在这里。 https://github.com/weliwita/IdentityServer4.Samples/tree/40844310

+0

伟大..现在工作正常..我不能相信我是如何忘记将其添加到范围..谢谢无论如何.. –

+0

@muhammadwaqas我认为你应该接受答案 – Learner

2

变化new Claim("role","FreeUser")new Claim(ClaimTypes.Role, "FreeUser")

或者创建一个像这样的政策:

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

和我们电子邮件:

Authorize[(Policy = "FreeUser")] 
+0

感谢您的回复,我已经尝试了两种方法,但结果相同,如果在创建API请求时添加策略,则会向API发出两个请求,第一个请求会显示204 [无内容]状态代码,而第二个失败与403 ..在索赔的情况下,结果是一样的403 ..有我失踪的东西?.. –