如何使用IdentityServer4进行微服务架构的基于角色的授权?

时间:2019-06-10 02:06:52

标签: c# asp.net-mvc authorization identityserver4 roles

历史记录:
我使用IdentityServer4开发了微服务的身份验证和授权,但是授权有问题。 我有两项服务:
-IdentityServer4服务,这是我的身份验证服务
-测试MVC项目

我成功连接了这些服务并使用混合流,并且身份验证工作也成功完成,并且我的角色也可以正常工作,因为我在身份验证服务侧使用自定义ProfileService在JWT令牌中包含了角色。

问题情况:
1.用户没有任何身份验证令牌。尝试在MVC网站上使用具有[Authorize(Roles = "Admin")]属性的打开页面,然后重定向到Auth服务上的页面。 2.用户输入登录名和密码。
3.使用Role = Admin获得令牌,重定向回Auth服务上的MVC站点。
4.为页面打开的用户,因为他具有管理员角色。
5.从身份验证服务的管理员角色中删除用户。
6.重新加载页面,并再次为该用户打开页面,这是正确的,因为他具有管理员角色。

问题:在身份验证服务端更改角色或声明后如何实现令牌?

IdentityServer配置:

public static IEnumerable<Client> GetClients()
        {
            return new Client[]
            {
                new Client
                {
                    ClientId = "Epp.Web.Mvc",
                    ClientName = "Единый Портал Потребителей",
                    AllowedGrantTypes = new List<string>{GrantType.Hybrid},
                    ClientSecrets = new List<Secret>
                    {
                        new Secret("secret".Sha256())
                    },
                    RequireConsent = false,
                    AllowAccessTokensViaBrowser = true,
                    AlwaysIncludeUserClaimsInIdToken = true,
                    AlwaysSendClientClaims = true,
                    AllowedScopes =
                    {
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile,
                        "epp",
                        "roles"
                    },
                    RedirectUris = new List<string>
                    {
                        "http://localhost:5002/signin-oidc",
                        "https://localhost:5003/signin-oidc"
                    },
                    PostLogoutRedirectUris = new List<string>{ "http://localhost:5002/signout-callback-oidc" },
                    AccessTokenLifetime = 60 * 10 
                }
            };
        }

MVC启动:

services.AddAuthentication(options =>
                {
                    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = "oidc";
                })
                .AddCookie(setup => setup.ExpireTimeSpan = TimeSpan.FromHours(2))
                .AddOpenIdConnect("oidc", options =>
                    {
                        options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                        options.Authority = "https://localhost:5001";
                        options.ClientId = "Epp.Web.Mvc";
                        options.ResponseType = "code id_token";
                        options.ClientSecret = "secret";

                        options.GetClaimsFromUserInfoEndpoint = true;
                        options.SaveTokens = true;
                        options.RequireHttpsMetadata = false;


                        options.Scope.Add(IdentityServerConstants.StandardScopes.OpenId);
                        options.Scope.Add(IdentityServerConstants.StandardScopes.Profile);
                        options.Scope.Add("epp");
                        options.Scope.Add("roles");
                        options.TokenValidationParameters = new TokenValidationParameters
                        {
                            NameClaimType = "name",
                            RoleClaimType = "role"
                        };
                    });

2 个答案:

答案 0 :(得分:1)

实际上,该问题并非专门针对OpenId-Connect或Identity Server。关于将某些缓存(安全)数据保留多长时间,这是一个更普遍的问题。 JWT在设计上是不可变的,因此您可以将其视为一种缓存。一旦缓存的项(或jwt)过期,我们将获得一个新项。因此,唯一的解决方案是为您的承载令牌设置一个合理的短到期时间,并使用刷新来“实现”承载。

我个人看不到将角色更改为给定服务的范围有什么帮助。那是另一回事。我们可以或多或少不断地定义application1有权访问service1.write范围,并由此限制All but application1' users来访问API。但是,如果该应用程序具有通用性,该怎么办?这里没有答案。

另一个建议是使用参考标记,并在必要时使它们无效。好吧,你可以做。但是默认情况下,API会缓存参考令牌验证的结果,因此...我们在一个新地方遇到了同样的问题。

应该起作用的是将基于角色的授权转移到每个服务中,如@VidmantasBlazevicius所建议的那样,但是在服务内部,您很可能又有一些缓存,因此您必须再次考虑如何在必要时使它无效。

答案 1 :(得分:0)

我看到了两种实现方法,

  1. 您可以在角色/权限发生更改时用户参考令牌流并使令牌无效。检查链接http://docs.identityserver.io/en/latest/topics/reference_tokens.html

  2. 或者如@Vidmantas Blazevicius所述,将基于角色的授权作业移至各自的服务,而不是在身份服务器上进行中继。