[英]How do role-based authorization using identityserver4 for microservices architecture?
Prehistory: 史前史:
I develop authentication and authorization for microservices using IdentityServer4, but have problem with authorization. 我使用IdentityServer4开发了微服务的身份验证和授权,但是授权有问题。 I have two services: 我有两项服务:
- service with identityserver4, it's my auth service -IdentityServer4服务,这是我的身份验证服务
- test MVC project -测试MVC项目
I successfully connect these services and use Hybrid flow, and authentication work successfully, and also my roles works, because I include roles in JWT token using custom ProfileService on auth service side. 我成功连接了这些服务并使用混合流,并且身份验证也成功完成,并且我的角色也可以正常工作,因为我在auth服务端使用自定义ProfileService在JWT令牌中包含了角色。
Problem situation: 问题情况:
1. User have not any auth token. 1.用户没有任何身份验证令牌。 Try open page with [Authorize(Roles = "Admin")]
attribute on MVC site and redirect to page on Auth service. 尝试在MVC网站上使用[Authorize(Roles = "Admin")]
属性打开页面,然后重定向到Auth服务上的页面。 2. User enter login and password. 2.用户输入登录名和密码。
3. Got token with Role=Admin, redirect back to MVC site on Auth service. 3.使用Role = Admin获得令牌,重定向回Auth服务上的MVC站点。
4. Page opened for user, because he had Admin role. 4.为用户打开页面,因为他具有管理员角色。
5. Remove user from Admin role on Auth Service. 5.从身份验证服务的管理员角色中删除用户。
6. Reload page and page again opened fine for this user, and it's correct, because in token he had role admin. 6.重新加载页面,然后再次为该用户打开页面,这是正确的,因为他具有管理员角色。
Question: How I can actualize token after change roles or claims on auth service side? 问:在身份验证服务端更改角色或声明后,如何实现令牌?
IdentityServer Config: 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 Startup: 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"
};
});
Actually the question is not specifically about OpenId-Connect, nor Identity server. 实际上,问题不仅仅与OpenId-Connect有关,也不与Identity Server有关。 It's more a generic question about how long to keep some cached (security) data. 关于将某些缓存(安全)数据保留多长时间,这是一个更普遍的问题。 JWT is immutable by design, so you can treat it as a kind of cache. JWT在设计上是不可变的,因此您可以将其视为一种缓存。 Once the cached item (or a jwt) expires, we get a new one. 一旦缓存的项(或jwt)过期,我们将获得一个新项。 So the only solution is to set a reasonably short expiration for your bearer token and use a refresh one to "actualize" the bearer. 因此,唯一的解决方案是为您的承载令牌设置一个合理的短到期时间,并使用刷新来“实现”承载。
I personally can't see how changing roles to scopes for a given service can help. 我个人看不到将角色更改为给定服务的范围有什么帮助。 That's about a bit different thing. 那是另一回事。 We can more or less constantly define that application1
has access to service1.write
scope, and by that restrict All but application1' users
from access to the API. 我们可以或多或少不断地定义application1
有权访问service1.write
范围,从而限制了All but application1' users
对API的访问。 But what if the app is universal? 但是,如果该应用程序具有通用性,该怎么办? No answer here. 这里没有答案。
Another suggestion was to use reference tokens and invalidate when necessary. 另一个建议是使用参考标记,并在必要时使之无效。 Well, you could do. 好吧,你可以做。 But by default the API caches the reference token validation' result, so... We get the same problem in a new place. 但是默认情况下,API会缓存参考令牌验证的结果,因此...我们在一个新地方遇到了同样的问题。
What should work is moving role based authorization into each service, as @VidmantasBlazevicius suggested, but again inside the service you most likely have some cache, so you again have to think how to invalidate it when necessary. 正如@VidmantasBlazevicius所建议的那样,应该将基于角色的授权移动到每个服务中,但是再次在该服务内部您很可能拥有一些缓存,因此您必须再次考虑如何在必要时使它无效。
I see 2 way to do it as below, 我看到以下两种方法
You can user reference token flow and invalidate token when changes occurs in your role/rights. 您可以在角色/权限发生更改时用户参考令牌流并使令牌无效。 Check link http://docs.identityserver.io/en/latest/topics/reference_tokens.html 检查链接http://docs.identityserver.io/en/latest/topics/reference_tokens.html
Or as mentioned by @Vidmantas Blazevicius, move role based authorization job to respective service rather than relay on identity server. 或如@Vidmantas Blazevicius所述,将基于角色的授权作业移至各自的服务,而不是在身份服务器上进行中继。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.