如何使用 Spring 安全模拟身份验证和授权

How to mock authentication and authorization with Spring Security

我有一个 spring-boot REST API 应用程序。 REST 端点受 spring-security.

保护

这是spring-security的配置:

protected void configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity
            .exceptionHandling().authenticationEntryPoint(new CustomForbiddenErrorHandler())
            .and()

            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()

            .authorizeRequests()
            .antMatchers("/api/**").authenticated() // HTTP 403 if the request is not authenticated
            .antMatchers("/**").permitAll();
}

它工作正常。如果我在 HTTP header 上没有 auth-token 的情况下进行休息调用,我会返回正确的 HTTP 错误代码。

我可以强制 spring 以某种方式添加一个 self auth-token 如果它没有按顺序显示,这样我就可以在没有自己的访问管理系统的情况下进行 REST 调用吗?稍后安装。

我不是在问如何编写 JUnit 测试。我要问的是如何动态生成模拟 auth-token 并将其添加到请求中(如果它不存在)。

您可以覆盖现有的身份验证过滤器,或创建新的自定义过滤器,以检查请求是否包含不记名令牌。根据结果​​,您可以按原样处理请求,也可以使用自定义身份验证对象扩充请求。

查看 OAuth2AuthenticationProcessingFilter,这会从传入请求中提取 OAuth2 令牌并使用它来填充 Spring 安全上下文。您可以覆盖它的行为或创建一个新的过滤器,用您的模拟身份验证对象填充安全上下文。

这是一个让您入门的示例代码:

@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    boolean debug = logger.isDebugEnabled();
    HttpServletRequest request = (HttpServletRequest)req;
    HttpServletResponse response = (HttpServletResponse)res;

    try {
        Authentication authentication = this.tokenExtractor.extract(request);
        if (Objects.isNull(authentication)) {
            final UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken("username", "password");

            authenticationToken.setDetails(Collections.singletonMap("user_uuid", userUuid.toString()));

            final OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(null, authenticationToken);

            // You can either ask your authenticatoin manager to authenticate these credentials or directly publish auth success event with your mock auth object.

            this.eventPublisher.publishAuthenticationSuccess(oAuth2Authentication);
            SecurityContextHolder.getContext().setAuthentication(oAuth2Authentication);

        } else {
            request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, authentication.getPrincipal());
            if (authentication instanceof AbstractAuthenticationToken) {
                AbstractAuthenticationToken needsDetails = (AbstractAuthenticationToken)authentication;
                needsDetails.setDetails(this.authenticationDetailsSource.buildDetails(request));
            }

            Authentication authResult = this.authenticationManager.authenticate(authentication);
            if (debug) {
                logger.debug("Authentication success: " + authResult);
            }

            this.eventPublisher.publishAuthenticationSuccess(authResult);
            SecurityContextHolder.getContext().setAuthentication(authResult);
        }