Spring Security:为什么身份验证扩展主体?

Cem*_*emo 5 spring spring-security

Spring Security假设Authentication是主体。

public interface Authentication extends Principal, Serializable {}
Run Code Online (Sandbox Code Playgroud)

HttpServletRequest具有getUserPrincipal方法,该方法负责访问主体对象。

让我们考虑这种情况:

public interface RealPrincipal extends Principal {
   public Integer getId();
}
Run Code Online (Sandbox Code Playgroud)

通用模块A具有Real Principal接口和实现。

模块A使用通用模块A,Servlet Api,并且不依赖于Spring Security:

模块B使用通用模块A,Servlet Api并配置Spring Security。该模块负责安全性和UserDetails的实现。

Web A使用模块A和模块B。

为了使用请求方法,我最终得到了这样的实现:

public ModelAndView someRequestHandler(Principal principal) {
   User activeUser = (User) ((Authentication) principal).getPrincipal();
   ...
}
Run Code Online (Sandbox Code Playgroud)

这迫使我必须对模块A和其他模块依赖Spring Security。我相信适当的servlet api抽象不应依赖于spring安全性。request.getUserPrincipal应该返回真实的主体。

请解释为什么org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper返回

验证而不是Real Principal

编辑:我已将通用模块A添加到我的方案,并更新了模块B负责安全性。

Rob*_*nch 5

正如 Luke 所说,Spring Security 使用主体身份验证,因为它实现了主体。它不使用 Authentication#getPrincipal() 因为它不能保证是主体(它是对象)。事实上,在大多数情况下,Spring Security 的 Authentication#getPrincipal() 返回一个 User (不实现Principal)、框架用户提供的自定义 UserDetails 或一个 String。

如果您希望 Spring Security 处理此问题,您可能需要按照 Luke 的建议使用 HttpServletRequestWrapper 来实现此逻辑。例如,您可以执行以下操作:

public RealPrincipalFilter extends OncePerRequestFilter {

    public void doFiter(HttpServletRequest request, HttpServletResponse response, FilterChain) {
        chain.doFilter(new RealPrincipalRequestWrapper(request), response);
    }

    private static final class RealPrincipalRequestWrapper 
          extends HttpServletRequestWrapper {
        public Principal getUserPrincipal() {
            Authentication auth = (Authentication) super.getPrincipal();
            return auth == null ? null : (RealPrincipal) auth.getPrincipal()
        }
    }
}

@Configuration
@EnableWebSecurity
public WebSecurityConfig extends WebSecurityConfigurerAdapter {
    public configure(HttpSecurity http) {
        http
            // ... other config ...
            .addFilterAfter(new RealPrincipalFilter(), SecurityContextHolderAwareRequestFilter.class);
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

或者,看看我对您的其他问题的回答,了解与 Spring MVC 集成的选项 - Injecting Custom Primary to Controllers by Spring Security