当前位置: 首页 > 知识库问答 >
问题:

Spring Boot、keycloak和基本身份验证在同一个项目中一起使用

郤玉书
2023-03-14

我有一个问题与Spring开机的安全。我想要的是在Spring Boot中同时对同一个项目有两个不同的身份验证。一个是SSO(keycloak authentication),用于除'/download/export/*'之外的所有路径,另一个是Spring Boot basic authentication。下面是我的配置文件:

@Configuration 
@EnableWebSecurityp 
public class MultiHttpSecurityConfig {
@Configuration
@Order(1)
public static class DownloadableExportFilesSecurityConfig extends WebSecurityConfigurerAdapter
{
@Override
protected void configure(HttpSecurity http) throws Exception
{
    http
            .antMatcher("/download/export/test")
            .authorizeRequests()
            .anyRequest().hasRole("USER1")
            .and()
            .httpBasic();    }

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

@Configuration
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
public static class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter
{
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
{
    auth.authenticationProvider(keycloakAuthenticationProvider());
}

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

@Override
protected void configure(HttpSecurity http) throws Exception
{
    super.configure(http);
    http
            .regexMatcher("^(?!.*/download/export/test)")
            .authorizeRequests()
            .anyRequest().hasAnyRole("ADMIN", "SUPER_ADMIN")
            .and()
            .logout().logoutSuccessUrl("/bye");

}
}

上面代码的问题是:如果我请求url'/download/export/test',它会问我用户名/密码(基本身份验证)。成功登录后,它再次询问我用户名/密码(但这次是keycloak身份验证),即使请求的url从SecurityConfig(keycloak Adapter)中排除。

它只给我一个警告:

2016-06-20 16:31:28.771  WARN 6872 --- [nio-8087-exec-6] o.k.a.s.token.SpringSecurityTokenStore   : Expected a KeycloakAuthenticationToken, but found org.springframework.security.authentication.UsernamePasswordAuthenticationToken@3fb541cc: Principal: org.springframework.security.core.userdetails.User@36ebcb: Username: user; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER1; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: 4C1BD3EA1FD7F50477548DEC4B5B5162; Granted Authorities: ROLE_USER1

共有1个答案

楚良平
2023-03-14

您遇到的问题是KeycloakAuthenticationProcessingFilter.java拦截每个带有HTTP授权头的请求。如果您的请求没有通过Keycloak进行身份验证(即使您已经通过任何其他身份验证提供者进行了身份验证!-在您的情况下使用基本身份验证),您将始终被重定向到Keycloak的登录页面(在您的情况下),或者获得未经授权的401(如果Keycloak.json中的Keycloak客户机配置为只承载)。

默认情况下,如果请求匹配KeycloakAuthenticationProcessingFilter.default_request_matcher,则调用KeycloakAuthenticationProcessingFilter.java:

public static final RequestMatcher DEFAULT_REQUEST_MATCHER =
    new OrRequestMatcher(
            new AntPathRequestMatcher(DEFAULT_LOGIN_URL),
            new RequestHeaderRequestMatcher(AUTHORIZATION_HEADER),
            new QueryParamPresenceRequestMatcher(OAuth2Constants.ACCESS_TOKEN)
    );

这意味着任何匹配DEFAULT_LOGIN_URL(/sso/login)或包含Authorization HTTP头(在您的例子中)或将access_token作为查询参数的请求都将由KeycloakAuthenticationProcessingFilter.java处理。

这就是为什么您必须用自己的实现替换RequestHeaderRequestMatcher(AUTHORIZATION_HEADER),当用基本身份验证对请求进行身份验证时,该实现将跳过对KeyCloakAuthenticationProcessingFilter.java的调用。

下面是一个完整的解决方案,它使您能够在相同的路径上同时使用基本身份验证和Keycloak身份验证。特别注意IgnoreKeycloakProcessingFilterRequestMatcher实现,它正在替换默认的RequestHeaderRequestMatcher。该匹配器将只匹配包含授权HTTP标头的请求,该标头的值没有以“basic”作为前缀。

在下面的示例中,具有tester角色的用户可以访问/download/export/test,而具有adminsuper_admin角色的用户可以使用所有其他路径(在您的情况下,我假设这些角色是Keycloak服务器上的帐户)。

@KeycloakConfiguration
public class MultiHttpSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("tester")
                .password("testerPassword")
                .roles("TESTER");
        auth.authenticationProvider(keycloakAuthenticationProvider());
    }

    @Bean
    @Override
    protected KeycloakAuthenticationProcessingFilter keycloakAuthenticationProcessingFilter() throws Exception {
        RequestMatcher requestMatcher =
                new OrRequestMatcher(
                        new AntPathRequestMatcher(DEFAULT_LOGIN_URL),
                        new QueryParamPresenceRequestMatcher(OAuth2Constants.ACCESS_TOKEN),
                        // We're providing our own authorization header matcher
                        new IgnoreKeycloakProcessingFilterRequestMatcher()
                );
        return new KeycloakAuthenticationProcessingFilter(authenticationManagerBean(), requestMatcher);
    }

    // Matches request with Authorization header which value doesn't start with "Basic " prefix
    private class IgnoreKeycloakProcessingFilterRequestMatcher implements RequestMatcher {
        IgnoreKeycloakProcessingFilterRequestMatcher() {
        }

        public boolean matches(HttpServletRequest request) {
            String authorizationHeaderValue = request.getHeader("Authorization");
            return authorizationHeaderValue != null && !authorizationHeaderValue.startsWith("Basic ");
        }
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http.authorizeRequests()
                .antMatchers("/download/export/test")
                .hasRole("TESTER")
                .anyRequest()
                .hasAnyRole("ADMIN", "SUPER_ADMIN")
                .and()
                .httpBasic();
    }

    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
    }
}
 类似资料:
  • Keycloak是否支持基本身份验证(包含单词basic word后跟空格和base64编码的字符串username:password的授权头),如果支持,我如何为它配置领域和客户端设置?我想用Keycloak保护我的rest api,并支持基本身份验证作为一个选项。

  • 几天没有任何进展,我需要你的帮助。 使用GWT,我试图与REST服务器通信,服务器位于不同的URL上(需要CORS)<我的配置:服务器spring boot 1.3.3 客户端-GWT 1.7-restygwt 2.0.3 当我在Spring中禁用安全性时,我可以在我的GWT客户端中获取数据。 但是当我启用它时,我总是收到401个请求。REST URL请求直接在Web浏览器中工作(带有其身份验证对

  • 我是Spring Security的新手 我有Sprint Boot Rest API项目,它公开了某些API。我已经为所有API实现了基于承载令牌的身份验证。例如 /user、 /resource、 /appointment 现在,对于特定控制器的几个api,我希望实现基本身份验证。这些API将被另一个不公开的服务使用。为了保证API的安全性,我希望为这些apis提供基本身份验证。例如 /int

  • 问题内容: 以下代码成功连接到我的Ruby on Rails API,并使用AFNetworking返回JSON。我需要做什么来进行编辑以传递用户名和密码,以便我的API可以使用HTTP基本身份验证? 我已经阅读了他们的文档,但是我对Objective-C和AFNetworking还是陌生的,目前还没有意义。 问题答案: AFNetworking 2.x的答案已更新 对于AFNetworking

  • 我在调试身份验证问题时遇到了这个代码片段: 我在调试和摆弄用户凭证时注意到,如果第一个身份验证提供者(即< code > userdailsservice )无法对我的用户进行身份验证,那么就会远程调用我的LDAP服务器来尝试对我的用户进行身份验证。但是,如果第一个身份验证提供者成功地对我的用户进行了身份验证,则不会调用第二个身份验证提供者。 我的问题是,列出这些身份验证提供者的工作方式是否使得如

  • 问题内容: 从HttpClient 4.3开始,我一直在使用HttpClientBuilder。我正在连接到具有基本身份验证的REST服务。我将凭据设置如下: 但是,这不起作用(我正在使用的REST服务返回401)。怎么了? 问题答案: 从此处的 抢先身份验证 文档中: http://hc.apache.org/httpcomponents-client- ga/tutorial/html/aut