使用 Spring Security OAuth2 和 Okta 处理基于 url 的 RBAC
Handling url based RBAC with Spring Security OAuth2 and Okta
我在 Okta 上安装了应用程序和授权服务器。我添加了两个组,即admin
和users
。身份验证流程工作正常,但是当我尝试打印角色时,我得到如下输出
[SCOPE_address, SCOPE_phone, SCOPE_offline_access, SCOPE_openid, ROLE_USER, SCOPE_email, SCOPE_profile]
打印角色的Java代码如下:
@RequestMapping("/securedPage")
public String securedPage(Model model, Principal principal) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Set<String> roles = authentication.getAuthorities().stream()
.map(r -> r.getAuthority()).collect(Collectors.toSet());
System.out.println(roles);
return roles.toString();
}
application.properties
okta.oauth2.client-id=<client-id>
okta.oauth2.client-secret=<client-secret>
okta.oauth2.issuer=<issuer-url>
okta.oauth2.redirect-uri=/login
okta.oauth2.roles-claim=groups
server.port=9222
logging.level.org.springframework.security=TRACE
当我访问登录页面并输入 username
和 password
时,角色没有显示。但奇怪的是,我看到 ROLE_USER
但我已将用途添加到 users
组中。
我正在遵循本指南 https://developer.okta.com/blog/2017/10/13/okta-groups-spring-security
。我不确定,如何在 Spring 安全中配置授权角色。
下面是Spring安全配置
@Configuration
public class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter{
@Bean
GrantedAuthorityDefaults grantedAuthorityDefaults() {
return new GrantedAuthorityDefaults(""); // Remove the ROLE_ prefix
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login();
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example.demo</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR8</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.okta.spring</groupId>
<artifactId>okta-spring-boot-starter</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
uestMatcher : Checking match of request : '/securedPage'; against '/'
2021-01-09 00:41:57.674 DEBUG 21292 --- [nio-9222-exec-4] o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /securedPage; Attributes: [authenticated]
2021-01-09 00:41:57.678 DEBUG 21292 --- [nio-9222-exec-4] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken@dffd3eb: Principal: Name: [00u3g2nr7ISCACRyk5d6], Granted Authorities: [[ROLE_USER, SCOPE_address, SCOPE_email, SCOPE_offline_access, SCOPE_openid, SCOPE_phone, SCOPE_profile]], User Attributes: [{at_hash=dHbIlPZ1tUzL-y5vmVb1cQ, sub=00u3g2nr7ISCACRyk5d6, zoneinfo=America/Los_Angeles, ver=1, email_verified=true, amr=["pwd"], iss=https://dev-9729512.okta.com/oauth2/edukart, preferred_username=kishore@gmail.com, locale=en-US, given_name=kishore, nonce=FxcHjdKHTsisyWG8jiLgEbH84H2AxyCdISv5U0JyVA8, aud=[0oa3eaj576gLDYwsh5d6], updated_at=2021-01-07T19:46:08Z, idp=00o3ct0plX9rgiTmB5d6, auth_time=2021-01-08T18:48:46Z, name=kishore kumar, exp=2021-01-08T20:11:54Z, family_name=kumar, iat=2021-01-08T19:11:54Z, email=kishore@gmail.com, jti=ID.xLH6W1loE_ELRLCWEuyGHV42-pkw3eCDqfNVlyQOfnc}]; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@43458: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: D028931C57C35976D9AB6FC2C9543B4B; Granted Authorities: ROLE_USER, SCOPE_address, SCOPE_email, SCOPE_offline_access, SCOPE_openid, SCOPE_phone, SCOPE_profile
我哪里出错了以及如何使用 Okta 组调试 Spring 安全角色。
更新:
我将 okta-spring-boot-starter
版本更新为 1.4.0
,现在我可以看到分配给用户的 admins
角色。
roles :: [SCOPE_address, Everyone, SCOPE_phone, SCOPE_offline_access, SCOPE_openid, ROLE_USER, SCOPE_email, SCOPE_profile, admins]
问题:
- 为什么仅当在
include in token type
中使用 ID-Token
配置声明时才获取角色,而不是在 Okta 中将其作为 ACCESS_TOKEN
的一部分发送时
- 我在声明选项卡中没有看到将声明同时设置为 ID-TOKEN 和 ACCESS TOKEN 的选项。它是一个下拉菜单,我只能选择一个。
- 为什么授予的权限显示为
admins
而不是 ROLE_ADMINS
Principal :: Name: [00u40teh2owUKq5ZL5d6], Granted Authorities: [[Everyone, ROLE_USER, SCOPE_address, SCOPE_email, SCOPE_offline_access, SCOPE_openid, SCOPE_phone, SCOPE_profile, admins]], User Attributes: [{at_hash=uB-Gcqt-H6ezmv8KpIpx_g, sub=00u40teh2owUKq5ZL5d6, zoneinfo=America/Los_Angeles, ver=1, email_verified=true, amr=["pwd"], iss=https://dev-7858070.okta.com/oauth2/default, groups=["Everyone","admins"], preferred_username=ramesh@gmail.com, locale=en-US, given_name=ramesh, nonce=KXqGlhOj5ZVoChXo-ATjoHW-9ABAcEi5AnukAGXxg78, aud=[0oa3mz4mtisXjRJf85d6], updated_at=2021-01-20T03:17:42Z, idp=00o3myy20pqywuN5o5d6, auth_time=2021-01-21T03:02:46Z, name=ramesh kumar, exp=2021-01-21T04:02:49Z, family_name=kumar, iat=2021-01-21T03:02:49Z, email=ramesh@gmail.com, jti=ID.XQ4cKdIMuQKJv941EkYyDFJDCtKFAzaItPdyLPkMXPQ}] roles :: [SCOPE_address, Everyone, SCOPE_phone, SCOPE_offline_access, SCOPE_openid, ROLE_USER, SCOPE_email, SCOPE_profile, admins]
看看您提到的博客 post 中的“授权服务器”部分:
https://developer.okta.com/blog/2017/10/13/okta-groups-spring-security#authorization-server
post 使用了这些库的旧版本,但请确保您定义了“组”声明。您可能需要将“include in token type”值设置为“both”(或者按照相同的步骤为“ID Token”创建一个)
这 post 可能早于 Spring 安全性中的 OIDC 支持。
让我们 posted,如果那是问题所在,我会调整 post 以提及它。
如果这没有帮助,请使用 Okta Admin/Developer 控制台中“授权服务器”配置页面上的“令牌预览”选项卡。
一切配置正确后,您应该会看到列出的“组”声明。
更新(回答其他问题):
ID 令牌与访问令牌声明
这与 OAuth 2.0 和 OIDC 规范有点相关。但 TL;DR 是旧版本的 Spring 安全性使用 OAuth 2.0 和访问令牌,较新版本可以使用 OIDC 和 ID 令牌。
还有其他流程也会使用访问令牌,有关这两者之间的差异以及哪些流程使用哪些令牌的更详细描述,请查看 Okta Dev YouTube Channel
这是我的错,我想念这一页。
您可以只为两种令牌类型创建声明。
它使用组中的名称,如果您希望它使用 ROLE_ADMIN
,您可以使用该名称创建一个 Okta 组。
我在 Okta 上安装了应用程序和授权服务器。我添加了两个组,即admin
和users
。身份验证流程工作正常,但是当我尝试打印角色时,我得到如下输出
[SCOPE_address, SCOPE_phone, SCOPE_offline_access, SCOPE_openid, ROLE_USER, SCOPE_email, SCOPE_profile]
打印角色的Java代码如下:
@RequestMapping("/securedPage")
public String securedPage(Model model, Principal principal) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Set<String> roles = authentication.getAuthorities().stream()
.map(r -> r.getAuthority()).collect(Collectors.toSet());
System.out.println(roles);
return roles.toString();
}
application.properties
okta.oauth2.client-id=<client-id>
okta.oauth2.client-secret=<client-secret>
okta.oauth2.issuer=<issuer-url>
okta.oauth2.redirect-uri=/login
okta.oauth2.roles-claim=groups
server.port=9222
logging.level.org.springframework.security=TRACE
当我访问登录页面并输入 username
和 password
时,角色没有显示。但奇怪的是,我看到 ROLE_USER
但我已将用途添加到 users
组中。
我正在遵循本指南 https://developer.okta.com/blog/2017/10/13/okta-groups-spring-security
。我不确定,如何在 Spring 安全中配置授权角色。
下面是Spring安全配置
@Configuration
public class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter{
@Bean
GrantedAuthorityDefaults grantedAuthorityDefaults() {
return new GrantedAuthorityDefaults(""); // Remove the ROLE_ prefix
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login();
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example.demo</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR8</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.okta.spring</groupId>
<artifactId>okta-spring-boot-starter</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
uestMatcher : Checking match of request : '/securedPage'; against '/'
2021-01-09 00:41:57.674 DEBUG 21292 --- [nio-9222-exec-4] o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /securedPage; Attributes: [authenticated]
2021-01-09 00:41:57.678 DEBUG 21292 --- [nio-9222-exec-4] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken@dffd3eb: Principal: Name: [00u3g2nr7ISCACRyk5d6], Granted Authorities: [[ROLE_USER, SCOPE_address, SCOPE_email, SCOPE_offline_access, SCOPE_openid, SCOPE_phone, SCOPE_profile]], User Attributes: [{at_hash=dHbIlPZ1tUzL-y5vmVb1cQ, sub=00u3g2nr7ISCACRyk5d6, zoneinfo=America/Los_Angeles, ver=1, email_verified=true, amr=["pwd"], iss=https://dev-9729512.okta.com/oauth2/edukart, preferred_username=kishore@gmail.com, locale=en-US, given_name=kishore, nonce=FxcHjdKHTsisyWG8jiLgEbH84H2AxyCdISv5U0JyVA8, aud=[0oa3eaj576gLDYwsh5d6], updated_at=2021-01-07T19:46:08Z, idp=00o3ct0plX9rgiTmB5d6, auth_time=2021-01-08T18:48:46Z, name=kishore kumar, exp=2021-01-08T20:11:54Z, family_name=kumar, iat=2021-01-08T19:11:54Z, email=kishore@gmail.com, jti=ID.xLH6W1loE_ELRLCWEuyGHV42-pkw3eCDqfNVlyQOfnc}]; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@43458: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: D028931C57C35976D9AB6FC2C9543B4B; Granted Authorities: ROLE_USER, SCOPE_address, SCOPE_email, SCOPE_offline_access, SCOPE_openid, SCOPE_phone, SCOPE_profile
我哪里出错了以及如何使用 Okta 组调试 Spring 安全角色。
更新:
我将 okta-spring-boot-starter
版本更新为 1.4.0
,现在我可以看到分配给用户的 admins
角色。
roles :: [SCOPE_address, Everyone, SCOPE_phone, SCOPE_offline_access, SCOPE_openid, ROLE_USER, SCOPE_email, SCOPE_profile, admins]
问题:
- 为什么仅当在
include in token type
中使用ID-Token
配置声明时才获取角色,而不是在 Okta 中将其作为 - 我在声明选项卡中没有看到将声明同时设置为 ID-TOKEN 和 ACCESS TOKEN 的选项。它是一个下拉菜单,我只能选择一个。
- 为什么授予的权限显示为
admins
而不是ROLE_ADMINS
ACCESS_TOKEN
的一部分发送时
Principal :: Name: [00u40teh2owUKq5ZL5d6], Granted Authorities: [[Everyone, ROLE_USER, SCOPE_address, SCOPE_email, SCOPE_offline_access, SCOPE_openid, SCOPE_phone, SCOPE_profile, admins]], User Attributes: [{at_hash=uB-Gcqt-H6ezmv8KpIpx_g, sub=00u40teh2owUKq5ZL5d6, zoneinfo=America/Los_Angeles, ver=1, email_verified=true, amr=["pwd"], iss=https://dev-7858070.okta.com/oauth2/default, groups=["Everyone","admins"], preferred_username=ramesh@gmail.com, locale=en-US, given_name=ramesh, nonce=KXqGlhOj5ZVoChXo-ATjoHW-9ABAcEi5AnukAGXxg78, aud=[0oa3mz4mtisXjRJf85d6], updated_at=2021-01-20T03:17:42Z, idp=00o3myy20pqywuN5o5d6, auth_time=2021-01-21T03:02:46Z, name=ramesh kumar, exp=2021-01-21T04:02:49Z, family_name=kumar, iat=2021-01-21T03:02:49Z, email=ramesh@gmail.com, jti=ID.XQ4cKdIMuQKJv941EkYyDFJDCtKFAzaItPdyLPkMXPQ}] roles :: [SCOPE_address, Everyone, SCOPE_phone, SCOPE_offline_access, SCOPE_openid, ROLE_USER, SCOPE_email, SCOPE_profile, admins]
看看您提到的博客 post 中的“授权服务器”部分:
https://developer.okta.com/blog/2017/10/13/okta-groups-spring-security#authorization-server
post 使用了这些库的旧版本,但请确保您定义了“组”声明。您可能需要将“include in token type”值设置为“both”(或者按照相同的步骤为“ID Token”创建一个)
这 post 可能早于 Spring 安全性中的 OIDC 支持。
让我们 posted,如果那是问题所在,我会调整 post 以提及它。
如果这没有帮助,请使用 Okta Admin/Developer 控制台中“授权服务器”配置页面上的“令牌预览”选项卡。 一切配置正确后,您应该会看到列出的“组”声明。
更新(回答其他问题):
ID 令牌与访问令牌声明 这与 OAuth 2.0 和 OIDC 规范有点相关。但 TL;DR 是旧版本的 Spring 安全性使用 OAuth 2.0 和访问令牌,较新版本可以使用 OIDC 和 ID 令牌。
还有其他流程也会使用访问令牌,有关这两者之间的差异以及哪些流程使用哪些令牌的更详细描述,请查看 Okta Dev YouTube Channel
这是我的错,我想念这一页。 您可以只为两种令牌类型创建声明。
它使用组中的名称,如果您希望它使用
ROLE_ADMIN
,您可以使用该名称创建一个 Okta 组。