首页 > 解决方案 > Keycloak 虚拟配置

问题描述

我有以 Keycloak 作为身份验证提供者的 Spring Boot 项目。是否可以为特定的弹簧配置文件创建“虚拟身份验证”?我想要配置文件'dummy-auth',它将始终将 KeycloakPrincipal 设置为一些虚拟用户。也许某种过滤器可以更换?我有我的密钥斗篷配置:

@KeycloakConfiguration
public class KeycloakSecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(keycloakAuthenticationProvider());
    }

    @Bean
    public KeycloakSpringBootConfigResolver keycloakSpringBootConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }

    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http.authorizeRequests()
                .anyRequest()
                .fullyAuthenticated();
    }
}

并且真的不知道如何实现这个虚拟身份验证。也许更好的选择是某种嵌套的 keycloak 实例?

标签: javaspringspring-bootkeycloak

解决方案


几个建议;

1.拥有多个个人资料

我会为不同的目的推荐不同的配置文件;keycloak,本地,keycloak-local。

钥匙斗篷

当您想要与身份提供者集成并将从 Keycloak 检索到的 Authenticated Object 设置为您的 Spring 上下文时,请使用此配置文件。

@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
@Profile( "keycloak" )
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter
{
    @Bean
    public KeycloakSpringBootConfigResolver keycloakConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }
    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy( )
    {
        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
    }

    @Autowired
    public void configureGlobal( AuthenticationManagerBuilder auth) throws Exception {
        KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
        auth.authenticationProvider(keycloakAuthenticationProvider);
    }

    @Override
    protected void configure( HttpSecurity http) throws Exception {
        super.configure(http);
        http.authorizeRequests()
            .antMatchers("/hello")
            .authenticated()
            .anyRequest()
            .permitAll();
    }

}

当地的

还创建一个本地配置文件,您不想随身份提供者一起发布但仍想将经过身份验证的用户注入到您的上下文中

@Configuration
@EnableWebSecurity
@ComponentScan( basePackageClasses = KeycloakSecurityComponents.class )
@Profile( "local" )
public class LocalSecurityConfig extends WebSecurityConfigurerAdapter
{

    @Override
    protected void configure( HttpSecurity http ) throws Exception
    {
        http.authorizeRequests( )
            .antMatchers( "/hello" )
            .authenticated( )
            .anyRequest( )
            .permitAll( )
            .and( )
            .formLogin( );
    }

    @Autowired
    public void configureGlobal( AuthenticationManagerBuilder auth )
        throws Exception
    {
        auth
            .inMemoryAuthentication( )
            .withUser( "user" )
            .password( passwordEncoder().encode( "password") )
            .roles( "USER" );
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

Keycloak-本地

或者更好的是,我们可以将真正的 Keycloak Authenticated 对象设置为特定配置文件中的上下文。如果您在上下文中需要更复杂的 Authentication 对象并且您附带 KeycloakAuthenticationToken,请使用此方法。否则本地配置文件也很好,因为这需要更多编码,但这也是工作示例:

创建一个过滤器,我们称之为LocalFilter。此过滤器将创建一个 KeycloakAuthenticationToken 并将其设置为 spring 上下文:

public class LocalFilter extends GenericFilterBean
{
    @Override
    public void doFilter( ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain )
        throws IOException, ServletException
    {
        SecurityContextHolder.getContext( ).setAuthentication( generateKeycloakToken( "stackoverflow.com", "ROLE_USER", "" ) );
        filterChain.doFilter(servletRequest, servletResponse);
    }

    public static KeycloakAuthenticationToken generateKeycloakToken( String org, String roles, String permissions )
    {
        AccessToken accessToken = new AccessToken( );
        if ( org != null && !org.isEmpty( ) )
        {
            accessToken.setOtherClaims( "org", org );
        }
        if ( permissions != null && !permissions.isEmpty( ) )
        {
            accessToken.setOtherClaims( "permissions", permissions );
        }
        RefreshableKeycloakSecurityContext rksc =
            new RefreshableKeycloakSecurityContext( null, null, UUID.randomUUID( ).toString( ), accessToken, null, null,
                null );
        Set<String> rolesSet = new HashSet<>( );
        String[] roleArr = roles.split( "," );
        for ( String role : roleArr )
        {
            rolesSet.add( role.trim( ) );
        }
        KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal = new KeycloakPrincipal<>( "name", rksc );
        Collection<GrantedAuthority> authorities = generateGrantedAuthority( roles );
        return new KeycloakAuthenticationToken( new SimpleKeycloakAccount( principal, rolesSet, rksc ), false,
            authorities );
    }

    public static Collection<GrantedAuthority> generateGrantedAuthority( String roles )
    {
        Collection<GrantedAuthority> authorities = new ArrayList<>( );
        for ( String role : roles.split( "," ) )
        {
            authorities.add( new SimpleGrantedAuthority( role.trim( ) ) );
        }
        return authorities;
    }
}

并在您的 SecurityConfig 中配置过滤器:

@Configuration
@EnableWebSecurity
@ComponentScan( basePackageClasses = KeycloakSecurityComponents.class )
@Profile( "local-keycloak" )
public class LocalKeycloakSecurityConfig extends KeycloakWebSecurityConfigurerAdapter
{
    @Bean
    public KeycloakSpringBootConfigResolver keycloakConfigResolver( )
    {
        return new KeycloakSpringBootConfigResolver( );
    }

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

    @Autowired
    public void configureGlobal( AuthenticationManagerBuilder auth ) throws Exception
    {
        KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider( );
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper( new SimpleAuthorityMapper( ) );
        auth.authenticationProvider( keycloakAuthenticationProvider );
    }

    @Override
    protected void configure( HttpSecurity http ) throws Exception
    {
        super.configure( http );
        http.addFilterBefore(new LocalFilter(), UsernamePasswordAuthenticationFilter.class)
            .authorizeRequests( )
            .antMatchers( "/hello" )
            .authenticated( )
            .anyRequest( )
            .permitAll( );
    }
}

2. If Resource Server: Token 不与 Identity Provider 交互

如果您将客户端用作 Keycloak 的资源服务器,则有一种方法可以在不与身份提供者交互的情况下验证您的身份验证。按照步骤;

  • 生成 JWT(如果您需要一些样本或在任何地方生成它,您可以为 Keycloak 创建一个虚拟客户端并复制它,记下您的算法和公钥)
  • 如果您使用 Keycloak 生成 jwt,请从领域设置 -> 密钥 -> 复制公钥属于算法(默认为 RS256)复制您的公钥并将其保存到应用程序中的某个位置,例如:src/main/test/resources
  • 而不是用and来issuer-uri配置你的服务。通过这样做,您的服务将不会请求您的身份提供者来验证承载。public-keyjws-algorithm
  • 对于 spring security oauth2 库,这里是一个示例配置:
spring
  security:
    oauth2:
      resourceserver:
        jwt:
          public-key-location: classpath:jwt_public_key.json
          jws-algorithm: RS256 # this is default, you can skip setting it
  • 现在将您的令牌作为Bearer标头发送。

推荐阅读