Аутентификация на основе ролей не работает с Keycloak и Java SpringJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Аутентификация на основе ролей не работает с Keycloak и Java Spring

Сообщение Anonymous »

Я следовал этому руководству: https://www.baeldung.com/spring-boot-keycloak, чтобы настроить свое приложение Spring с помощью Keycloak. Аутентификация работает нормально, но когда я хочу добавить аутентификацию на основе ролей, например

Код: Выделить всё

.requestMatchers(new AntPathRequestMatcher("/api/v1/user/**")).hasRole("user")
Я всегда получаю следующую ошибку

Код: Выделить всё

Bearer error="insufficient_scope", error_description="The request requires higher privileges than provided by the access token.", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"
Я проверил авторы с помощью

Код: Выделить всё

SecurityContextHolder.getContext().getAuthentication().getAuthorities();
и есть только те, которые имеют префикс SCOPE_.
Я также проверил токен, и он возвращает это правильно

Код: Выделить всё

 "realm_access": {
"roles": [
"offline_access",
"uma_authorization",
"default-master-realm",
"user"
]
},
помимо других полей.
Это мой класс KeycloakConfig:

Код: Выделить всё

package com.motus.core.shared.config.security;

import com.motus.auth.constants.Authority;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority;
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.session.HttpSessionEventPublisher;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@EnableWebSecurity
@Configuration
public class KeycloakConfig {

private static final String GROUPS = "groups";
private static final String REALM_ACCESS_CLAIM = "realm_access";
private static final String ROLES_CLAIM = "roles";

@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}

@Bean
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(sessionRegistry());
}

@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http, KeycloakLogoutHandler keycloakLogoutHandler) throws Exception {
http.authorizeHttpRequests(auth -> auth
.requestMatchers(new AntPathRequestMatcher("/api/v1/public/**")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/api/v1/auth/**")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/api/v1/admin/**")).hasRole("admin")
.requestMatchers(new AntPathRequestMatcher("/api/v1/user/**")).hasRole("user")
.anyRequest().authenticated()
);
http.oauth2ResourceServer(oauth2 -> oauth2
.jwt(Customizer.withDefaults()));
http.oauth2Login(Customizer.withDefaults())
.logout(logout ->  logout.addLogoutHandler(keycloakLogoutHandler).logoutSuccessUrl("/"));

http.csrf(AbstractHttpConfigurer::disable);
http.cors(Customizer.withDefaults());

return http.build();
}

@Bean
public GrantedAuthoritiesMapper userAuthoritiesMapperForKeycloak() {
return authorities -> {
Set 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) realmAccess.get(ROLES_CLAIM);
mappedAuthorities.addAll(generateAuthoritiesFromClaim(roles));
} else if (userInfo.hasClaim(GROUPS)) {
Collection roles = userInfo.getClaim(
GROUPS);
mappedAuthorities.addAll(generateAuthoritiesFromClaim(roles));
}
} else {
var oauth2UserAuthority = (OAuth2UserAuthority) authority;
Map userAttributes = oauth2UserAuthority.getAttributes();

if (userAttributes.containsKey(REALM_ACCESS_CLAIM)) {
Map realmAccess = (Map) userAttributes.get(
REALM_ACCESS_CLAIM);
Collection roles = (Collection) realmAccess.get(ROLES_CLAIM);
mappedAuthorities.addAll(generateAuthoritiesFromClaim(roles));
}
}
return mappedAuthorities;
};
}

Collection generateAuthoritiesFromClaim(Collection roles) {
return roles.stream().map(role -> new SimpleGrantedAuthority("ROLE_" + role)).collect(
Collectors.toList());
}
}
Похоже, что GrantedAuthoritesMapper не вызывается, знаете почему?
Вот что я добавил в свой pom.xml:

Код: Выделить всё

org.springframework.boot
spring-boot-starter-oauth2-client


org.springframework.boot
spring-boot-starter-oauth2-resource-server

и вот что я добавил в свои свойства application.properties:

Код: Выделить всё

spring.security.oauth2.client.registration.keycloak.client-id=${KEYCLOAK_CLIENT_ID:test-backend}
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=${KEYCLOAK_AUTHORIZATION_GRANT_TYPE:password}
spring.security.oauth2.client.registration.keycloak.scope=${KEYCLOAK_SCOPE:openid}
spring.security.oauth2.client.provider.keycloak.issuer-uri=${KEYCLOAK_ISSUER_URI:http://localhost:8080/realms/master}
spring.security.oauth2.client.provider.keycloak.user-name-attribute=${KEYCLOAK_USER_NAME_ATTRIBUTE:username}
spring.security.oauth2.resourceserver.jwt.issuer-uri=${KEYCLOAK_RESOURCE_SERVER_JWT_ISSUER_URI:http://localhost:8080/realms/master}
Я получаю токен, используя http://localhost:8080/realms/master/pro ... nect/token
Затем я отправляю запрос в свое приложение с полученным токеном и всегда получаю упомянутую выше ошибку. Кто-нибудь знает, как это исправить?

Подробнее здесь: https://stackoverflow.com/questions/787 ... ava-spring
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»