微服务架构如何使用identityserver4进行基于角色的授权?
How do role-based authorization using identityserver4 for microservices architecture?
史前史:
我使用 IdentityServer4 为微服务开发身份验证和授权,但遇到授权问题。
我有两个服务:
- 使用 identityserver4 的服务,这是我的身份验证服务
- 测试 MVC 项目
我成功连接了这些服务并使用了混合流程,身份验证工作成功,我的角色也有效,因为我在身份验证服务端使用自定义 ProfileService 将角色包含在 JWT 令牌中。
问题情况:
1. 用户没有任何授权令牌。尝试在 MVC 站点上使用 [Authorize(Roles = "Admin")]
属性打开页面并重定向到 Auth 服务页面。
2. 用户输入登录名和密码。
3. 使用 Role=Admin 获得令牌,重定向回 Auth 服务上的 MVC 站点。
4. 为用户打开页面,因为他有管理员角色。
5. 将用户从 Auth Service 的 Admin 角色中删除。
6. 重新加载页面,页面再次为该用户正常打开,这是正确的,因为在令牌中他具有管理员角色。
问题:如何在身份验证服务端更改角色或声明后实现令牌?
身份服务器配置:
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 种方法,
您可以在 role/rights 中发生更改时让用户参考令牌流并使令牌无效。检查 link http://docs.identityserver.io/en/latest/topics/reference_tokens.html
或者如@Vidmantas Blazevicius 所述,将基于角色的授权作业移动到相应的服务,而不是在身份服务器上中继。
实际上这个问题并不是关于 OpenId-Connect,也不是关于身份服务器。这更像是一个关于将某些缓存(安全)数据保留多长时间的一般性问题。 JWT 在设计上是不可变的,因此您可以将其视为一种缓存。一旦缓存项(或 jwt)过期,我们就会得到一个新的。因此,唯一的解决方案是为您的不记名令牌设置一个合理的短到期时间,并使用刷新令牌 "actualize" 不记名。
我个人看不出将给定服务的角色更改为范围有何帮助。这是一个有点不同的事情。我们可以或多或少地不断定义 application1
可以访问 service1.write
范围,并由此限制 All but application1' users
访问 API。但是,如果该应用程序是通用的呢?这里没有答案。
另一个建议是使用引用令牌并在必要时使之失效。嗯,你可以的。但是默认情况下 API 缓存引用令牌验证的结果,所以......我们在新的地方遇到了同样的问题。
正如@VidmantasBlazevicius 所建议的那样,应该将基于角色的授权转移到每个服务中,但同样在服务内部您很可能有一些缓存,因此您必须再次考虑如何在必要时使其无效。
史前史:
我使用 IdentityServer4 为微服务开发身份验证和授权,但遇到授权问题。
我有两个服务:
- 使用 identityserver4 的服务,这是我的身份验证服务
- 测试 MVC 项目
我成功连接了这些服务并使用了混合流程,身份验证工作成功,我的角色也有效,因为我在身份验证服务端使用自定义 ProfileService 将角色包含在 JWT 令牌中。
问题情况:
1. 用户没有任何授权令牌。尝试在 MVC 站点上使用 [Authorize(Roles = "Admin")]
属性打开页面并重定向到 Auth 服务页面。
2. 用户输入登录名和密码。
3. 使用 Role=Admin 获得令牌,重定向回 Auth 服务上的 MVC 站点。
4. 为用户打开页面,因为他有管理员角色。
5. 将用户从 Auth Service 的 Admin 角色中删除。
6. 重新加载页面,页面再次为该用户正常打开,这是正确的,因为在令牌中他具有管理员角色。
问题:如何在身份验证服务端更改角色或声明后实现令牌?
身份服务器配置:
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 种方法,
您可以在 role/rights 中发生更改时让用户参考令牌流并使令牌无效。检查 link http://docs.identityserver.io/en/latest/topics/reference_tokens.html
或者如@Vidmantas Blazevicius 所述,将基于角色的授权作业移动到相应的服务,而不是在身份服务器上中继。
实际上这个问题并不是关于 OpenId-Connect,也不是关于身份服务器。这更像是一个关于将某些缓存(安全)数据保留多长时间的一般性问题。 JWT 在设计上是不可变的,因此您可以将其视为一种缓存。一旦缓存项(或 jwt)过期,我们就会得到一个新的。因此,唯一的解决方案是为您的不记名令牌设置一个合理的短到期时间,并使用刷新令牌 "actualize" 不记名。
我个人看不出将给定服务的角色更改为范围有何帮助。这是一个有点不同的事情。我们可以或多或少地不断定义 application1
可以访问 service1.write
范围,并由此限制 All but application1' users
访问 API。但是,如果该应用程序是通用的呢?这里没有答案。
另一个建议是使用引用令牌并在必要时使之失效。嗯,你可以的。但是默认情况下 API 缓存引用令牌验证的结果,所以......我们在新的地方遇到了同样的问题。
正如@VidmantasBlazevicius 所建议的那样,应该将基于角色的授权转移到每个服务中,但同样在服务内部您很可能有一些缓存,因此您必须再次考虑如何在必要时使其无效。