sky*_*yho 7 spring-boot keycloak
我已经配置了Keycloak的使用,而不使用弹簧适配器。因为它已被弃用。我在Keycloak的控制台中创建了:一个REALM,一个用户,并为用户添加角色。
....
keycloak:
container_name: blog
depends_on:
keycloakdb:
condition: service_healthy
environment:
DB_DATABASE: ${POSTGRESQL_DB}
DB_USER: ${POSTGRESQL_USER}
DB_PASSWORD: ${POSTGRESQL_PASS}
KEYCLOAK_USER: ${KEYCLOAK_USER}
KEYCLOAK_PASSWORD: ${KEYCLOAK_PASSWORD}
DB_VENDOR: ${DB_VENDOR}
DB_ADDR: ${DB_ADDR}
DEBUG_PORT: ${DEBUG_PORT}
DB_PORT: ${DB_PORT}
TZ: ${TZ}
DEBUG: ${DEBUG}
image: jboss/keycloak:latest
.....
Run Code Online (Sandbox Code Playgroud)
这是应用程序配置
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.guide</groupId>
<artifactId>keycloak-postgres-quick-guide</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>keycloak-postgres-quick-guide</name>
<description>keycloak-postgres-quick-guide</description>
<properties>
<java.version>17</java.version>
<testcontainers.version>1.17.6</testcontainers.version>
<snakeyaml.version>1.33</snakeyaml.version>
<keycloak.version>20.0.2</keycloak.version>
</properties>
<dependencies>
....
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
...
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
<version>${keycloak.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Run Code Online (Sandbox Code Playgroud)
@Configuration
@EnableWebSecurity(debug = true)
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final KeycloakLogoutHandler keycloakLogoutHandler;
@Bean
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests()
.requestMatchers("/customers*", "/users*")
.hasRole("READ")
.anyRequest()
.permitAll();
http.oauth2Login()
.and()
.logout()
.addLogoutHandler(keycloakLogoutHandler)
.logoutSuccessUrl("/");
return http.build();
}
}
Run Code Online (Sandbox Code Playgroud)
@GetMapping(path = "/customers")
public String customers(Principal principal, Model model) {
addCustomers();
Iterable<Customer> customers = customerRepository.findAll();
model.addAttribute("customers", customers);
model.addAttribute("username", principal.getName());
return "customers";
}
Run Code Online (Sandbox Code Playgroud)
spring:
security:
oauth2:
client:
provider:
keycloak:
issuer-uri: http://localhost:28080/auth/realms/SpringBootKeycloak
user-name-attribute: preferred_username
registration:
keycloak:
authorization-grant-type: authorization_code
client-id: loggin-app
scope: openid
Run Code Online (Sandbox Code Playgroud)
但是,当尝试访问受保护的资源时,我收到错误:
发送OAuth2AuthenticationToken [主体=名称:[user-spring-app],授予权限:[[OIDC_USER,SCOPE_email,SCOPE_openid,SCOPE_profile]],用户属性:[{at_hash=yGjLEXdKSgOC3J8_QfLyrw,sub=26e4c1c7-cb02-4628-bae9-7a370b53c06 7 ,email_verified=false,iss=http://localhost:28080/auth/realms/SpringBootKeycloak,typ=ID,preferred_username=user-spring-app,nonce=yzqik3W-aQtCjP6nQGt-N2CbnyI7O7smrt6mLOZNXY8,sid=07dbaa6a-826c-4139-a956 -62a477f6eefe,aud=[loggin-app],acr=1,azp=loggin-app,auth_time=2022-12-21T08:22:10Z,exp=2022-12-21T08:27:10Z,session_state=07dbaa6a-826c -4139-a956-62a477f6eefe,iat = 2022-12-21T08:22:10Z,jti = 93f19918-bc4a-4435-bbcd-578f7ca2ed36}],凭据= [受保护],经过身份验证= true,详细信息= WebAuthenticationDetails [RemoteIpAddress = 127.0 .0.1,SessionId = A0B52BA34017AD4C0183CA1DD48420B8],授予权限= [OIDC_USER,SCOPE_email,SCOPE_openid,SCOPE_profile]]访问被拒绝的处理程序,因为访问被拒绝org.springframework.security.access.AccessDeniedException:访问被拒绝
我没有观察分配给用户的角色
主体=名称:[user-spring-app],授予权限:[[OIDC_USER,SCOPE_email,SCOPE_openid,SCOPE_profile]],
我试图了解keycloak的工作原理,但到目前为止只有零碎的信息。我发现的示例已过时(spring-boot- Keycloak-适配器现已弃用)。此外,我看到了不同的方法,有人使用hasAuthority(),有人使用hasRole(),但是,我不明白它与Keycloak 的工作原理。
我认为你必须:
我们开始做吧:
转到您的 keycloak 领域 -> 客户端 -> 打开您的客户端 -> 选项卡“客户端范围” -> 在表中单击“acme-dedicated”
添加映射器 -> 领域角色
取消选中并选中“添加到 ID 令牌”:该复选框可能默认处于选中状态,但并未激活,我们必须手动取消选中,然后再次选中。完成后,单击“保存”。
您可以转到“客户端范围” -> “评估”并验证该角色是否存在于 ID 令牌中。
为此,请将以下代码添加到您的 SecurityConfig 类中:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private static final String REALM_ACCESS_CLAIM = "realm_access";
private static final String ROLES_CLAIM = "roles";
@Bean
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.oauth2Login(Customizer.withDefaults());
...
return http.build();
}
@Bean
@SuppressWarnings("unchecked")
public GrantedAuthoritiesMapper userAuthoritiesMapperForKeycloak() {
return authorities -> {
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
var authority = authorities.iterator().next();
boolean isOidc = authority instanceof OidcUserAuthority;
if (isOidc) {
var oidcUserAuthority = (OidcUserAuthority) authority;
var userInfo = oidcUserAuthority.getUserInfo();
if (userInfo.hasClaim(REALM_ACCESS_CLAIM)) {
var realmAccess = userInfo.getClaimAsMap(REALM_ACCESS_CLAIM);
var roles = (Collection<String>) realmAccess.get(ROLES_CLAIM);
mappedAuthorities.addAll(generateAuthoritiesFromClaim(roles));
}
} else {
var oauth2UserAuthority = (OAuth2UserAuthority) authority;
Map<String, Object> userAttributes = oauth2UserAuthority.getAttributes();
if (userAttributes.containsKey(REALM_ACCESS_CLAIM)) {
var realmAccess = (Map<String, Object>) userAttributes.get(REALM_ACCESS_CLAIM);
var roles = (Collection<String>) realmAccess.get(ROLES_CLAIM);
mappedAuthorities.addAll(generateAuthoritiesFromClaim(roles));
}
}
return mappedAuthorities;
};
}
Collection<GrantedAuthority> generateAuthoritiesFromClaim(Collection<String> roles) {
return roles.stream().map(role -> new SimpleGrantedAuthority("ROLE_" + role)).collect(Collectors.toList());
}
}
Run Code Online (Sandbox Code Playgroud)
仅供参考:我不使用 keycloak java 适配器,因为它很快就会被弃用。我使用带有 spring security 的 oauth2-client 。这是我的 pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Run Code Online (Sandbox Code Playgroud)
祝你好运!
| 归档时间: |
|
| 查看次数: |
5411 次 |
| 最近记录: |