首页 > 解决方案 > doFilter() 重写方法 httpRequest.getUserPrincipal() 总是返回 NullPoint 异常

问题描述

我创建了 Spring Boot 应用程序。我使用了以下依赖项。Spring Boot 版本为 2.1.0.RELEASE

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

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

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

    <dependency>
        <groupId>org.keycloak</groupId>
        <artifactId>keycloak-saml-servlet-filter-adapter</artifactId>
        <version>4.5.0.Final</version>
    </dependency>

安全配置类如下所示。

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().antMatchers("/actuator").authenticated();
    http.headers().cacheControl().disable();
    http.csrf().disable();
    http.logout().logoutSuccessUrl("/assets/logout.html");
 }
 }

过滤器类如下所示:

@WebFilter(urlPatterns = "/*", initParams = {
    @WebInitParam(
            name = "keycloak.config.file",
            value = "./config/saml.xml"
    )})
public class SingleSignOnFilter extends SamlFilter {
    private static final String loginGc = "/gc/";
    private static final String logoutUrl = "/gc/assets/logout.html";

@Override
public void doFilter(ServletRequest request, ServletResponse response, 
FilterChain chain)throws IOException, ServletException {

    HttpServletRequest httpRequest = (HttpServletRequest) request;
    HttpServletResponse httpResponse = (HttpServletResponse) response;
    String requestPath = httpRequest.getRequestURI();

    boolean needAuthentication = !requestPath.equals(logoutUrl);
    boolean alreadyLoginGc = !requestPath.equals(loginGc);

    if (needAuthentication) {
        if (alreadyLoginGc) {
            super.doFilter(request, response, chain);
        } else {
            httpResponse.setHeader("Cache-Control", "no-cache, no 
                store");
            super.doFilter(request, response, chain);
        }
    } else {
        chain.doFilter(request, response);
    }
}
}

当我调用httpRequest.getUserPrincipal();此方法时,它将返回 Nullpoint 异常。

当我试图获得经过身份验证的用户时,它会返回annonymousUser

Authentication auth = SecurityContextHolder.getContext()
.getAuthentication();
 auth.getName();

Saml.xml 如下所示:

<keycloak-saml-adapter>
<SP entityID="https://localhost/gc" sslPolicy="NONE">
    <PrincipalNameMapping policy="FROM_NAME_ID"/>
    <IDP entityID="************************">
        <SingleSignOnService requestBinding="POST" 
validateResponseSignature="true"

bindingUrl="********************************"/>
        <SingleLogoutService requestBinding="REDIRECT" 
responseBinding="REDIRECT"

redirectBindingUrl="***************************"/>
        <Keys>
            <Key signing="true">
                <CertificatePem>
                    -----BEGIN CERTIFICATE-----
                    ##########################
                    ###### Dummy Data ########
                    ##########################
                    -----END CERTIFICATE-----
                </CertificatePem>
            </Key>
        </Keys>
    </IDP>
</SP>
</keycloak-saml-adapter>

标签: spring-bootspring-securitysaml-2.0keycloak

解决方案


我不确定您正在使用的过滤器实现是否处理下面的弹簧安全所需的逻辑,但很明显SecurityContextHolder没有填充,因为没有配置适配器来这样做。

Keycloak 提供了一个Spring Security Adapter,尝试使用它。它也会填充httpRequest.getUserPrincipal()


推荐阅读