且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

通过密钥克隆的Spring应用程序基本身份验证

更新时间:2023-01-09 12:28:25

这是一种通过具有资源所有者密码凭据流的keycloak openid向您的应用程序添加基本身份验证的方法.

Here is one way to add basic auth to your application over keycloak openid with Resource owner password credentials flow.

首先,您需要将其添加到pom.xml:

First of all you'll need to add this to pom.xml:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.keycloak.bom</groupId>
            <artifactId>keycloak-adapter-bom</artifactId>
            <version>4.2.0.Final</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

...

<dependencies>
...
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-spring-boot-starter</artifactId>
        </dependency>
...
</dependencies>

添加keycloak服务器属性:

Add keycloak server properties:

keycloak.auth-server-url=https://${keycloak.host}/auth/
keycloak.realm=master
keycloak.resource=${client.name}
keycloak.credentials.secret=${client.secret}
keycloak.enable-basic-auth=true
keycloak.bearer-only=true

enable-basic-auth实际上负责启用资源所有者密码凭据流.因此,每次您使用基本授权BasicAuthRequestAuthenticator发送请求时,都会从keycloak请求令牌.需要bearer-only来关闭访问代码流.每次您在没有基本授权(和外部授权会话)的情况下请求对安全资源的请求时,您都将被重定向到keycloak服务器-我们不希望这样.使用bearer-only,您将获得401.

enable-basic-auth is actually responsible for enabling resource owner password credentials flow. So, every time you'll send request with Basic Authorization BasicAuthRequestAuthenticator will request token from keycloak. bearer-only is needed to turn off access code flow. Every time you'd make a request to secured resource without basic authorization (and outside authotized session) you'd get redirected to keycloak server - we don't want that. With bearer-only you'll get 401.

最后一步是添加安全配置:

And last step is adding security configuration:

@Configuration
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
@EnableWebSecurity
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

    @Bean
    public KeycloakAuthenticationProvider authenticationProvider() {
        KeycloakAuthenticationProvider provider = new KeycloakAuthenticationProvider();
        provider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
        return provider;
    }

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

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http
                .csrf().disable()
                .exceptionHandling().authenticationEntryPoint((request, response, authException) -> {
                    response.addHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Restricted Content\"");
                    response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
                })
                .and()
                .authorizeRequests()
                .antMatchers("/admin/**").hasRole("admin")
                .anyRequest().permitAll();
    }
}

这里最有趣的部分是这样:

Most interesting part here is this:

        .exceptionHandling().authenticationEntryPoint((request, response, authException) -> {
            response.addHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Restricted Content\"");
            response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
        })

标准密钥斗篷AuthenticationEntryPoint实现将授权失败的情况下将WWW-Authenticate标头设置为String.format("Bearer realm=\"%s\"", realm).我需要将其设置为Basic realm="Restricted Content"以便弹出基本身份验证提示.如果要避免使用此提示(要添加自己的登录表单),请删除此部分.

Standard keycloak AuthenticationEntryPoint implementation is setting WWW-Authenticate header to String.format("Bearer realm=\"%s\"", realm) in case of authorization failure. I need it to be set to Basic realm="Restricted Content" for the basic auth prompt to pop up. If you want to avoid using this prompt (you want to add your own login form) - remove this part.