使用 Apache CXF 2.4 JAX-RS 和 Spring Security 3.2 获取用户名

Get user name with Apache CXF 2.4 JAX-RS and Spring Security 3.2

我使用 SecurityContextHolder 在我的 JAX-RS 资源中获取了用户名并且有效:

@Path("/myresource")
public class MyResoure {

     @Get
     public String getUserName() {
          return SecurityContextHolder.getContext().getAuthentication().getName();
     }
}

但我想将 SecurityContext 注入 class 字段(以编写 JUnit 测试)。我尝试了一些记录在案的方法:

使用 javax.ws.rs.core.SecurityContext 我得到 NullPointerException,因为 securityContext 总是 null

@Path("/myresource")
public class MyResoure {

    @Context
    private javax.ws.rs.core.SecurityContext securityContext;

    @Get
    public String getUserName() {
        return securityContext.getUserPrincipal().getName();
    }
}

使用 org.apache.cxf.security.SecurityContext(参见 Apache CXF documentation)我得到 NullPointerException,因为 securityContext.getUserPrincipal() 始终是 null

@Path("/myresource")
public class MyResoure {

    @Context
    private org.apache.cxf.security.SecurityContext securityContext;

    @Get
    public String getUserName() {
        return securityContext.getUserPrincipal().getName();
    }
}

使用 org.apache.cxf.jaxrs.ext.MessageContext(参见 Apache CXF documentation)我得到 NullPointerException,因为 messageContext.getSecurityContext().getUserPrincipal() 始终是 null

@Path("/myresource")
public class MyResoure {

    @Context
    private org.apache.cxf.jaxrs.ext.MessageContext messageContext;

    @Get
    public String getUserName() {
        return messageContext.getSecurityContext().getUserPrincipal().getName();
    }
}

使用 javax.servlet.http.HttpServletRequest 我得到 NullPointerException,因为 httpServletRequest.getUserPrincipal() 总是 null

@Path("/myresource")
public class MyResoure {

    @Context
    private javax.servlet.http.HttpServletRequest httpServletRequest;

    @Get
    public String getUserName() {
        return httpServletRequest.getUserPrincipal().getName();
    }

我找到了一些解决 JUnit 问题的方法:

  • SecurityContextHolder 中设置 SecurityContext(参见 )

    JUnit测试代码:

    public class MyResourceTest {
    
        private SecurityContext securityContextMock = mock(SecurityContext.class);
    
        @Before
        public void setUp() {
            SecurityContextHolder.setContext(securityContextMock);
        }
    
        @After
        public void tearDown() {
            SecurityContextHolder.clearContext();
        }
    }
    
  • 环绕 SecurityContextHolder(参见 )

    包装代码:

    public class MySecurityContextHolder {
        public SecurityContext getContext() {
            return SecurityContextHolder.getContext();
        }
    }
    

    资源码:

    @Path("/myresource")
    public MyResource {
    
        private MySecurityContextHolder mySecurityContextHolder;
    
        @Get
        public String getUserName() {
             return mySecurityContextHolder.getContext().getAuthentication().getName();
        }
    }
    
  • 使用 SecurityContextHolderStrategy(参见 SEC-1188

    Spring配置:

    <bean id="myResource" class="MyResource">
        <property name="securityContextHolderStrategy" >
            <bean class="org.springframework.security.context.SecurityContextHolder" factory-method="getContexHolderStrategy">
            </bean>
        </property>
    </bean>
    

    资源码:

    @Path("/myresource")
    public MyResource {
    
        private SecurityContextHolderStrategy securityContextHolderStrategy;
    
        @Get
        public String getUserName() {
             return securityContextHolderStrategy.getContext().getAuthentication().getName();
        }
    }
    
  • 使用 PowerMock(参见 )

获取用户名

  • javax.ws.rs.core.SecurityContext,
  • org.apache.cxf.security.SecurityContext,
  • org.apache.cxf.jaxrs.ext.MessageContext
  • javax.servlet.http.HttpServletRequest

我必须将 SecurityContextHolderAwareRequestFilter 添加到我的 springSecurityFilterChain

Spring配置:

<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
    <security:filter-chain-map path-type="ant">
        <security:filter-chain pattern="/**" filters="securityContextPersistenceFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor" />
    </security:filter-chain-map>
</bean>

使用安全命名空间配置或Java Configuration the filter is added by default, see Spring Security documentation:

  • servlet-api-provision Provides versions of HttpServletRequest security methods such as isUserInRole() and getPrincipal() which are implemented by adding a SecurityContextHolderAwareRequestFilter bean to the stack. Defaults to true.