首页 文章

IdentityServer4基于角色的授权

提问于
浏览
17

我正在尝试使用IdentityServer4实现“基于角色的授权”,以基于用户角色访问我的API .

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

我有以下解决方案结构:

  • IdentityServer

  • WebApi

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

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 这里我试图通过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

当我通过单击按钮(Call Api)向API发出请求时,我收到以下错误..
enter image description here

3 回答

  • 10

    鉴于您没有为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

    new Claim("role","FreeUser") 更改为 new Claim(ClaimTypes.Role, "FreeUser")

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

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

    并使用它:

    Authorize[(Policy = "FreeUser")]
    
  • 5

    我在这篇文章上写了一个样本

    Identity Server 4: adding claims to access token

    我已经使用角色测试并声称我也可以在客户端Web应用程序和API应用程序中使用[Authorize(Role =“SuperAdmin,Admin”)] .

相关问题