6

Spring Security 假设 Authentication 是 Principal 。

public interface Authentication extends Principal, Serializable {}

HttpServletRequest 有getUserPrincipal的方法负责访问主体对象

让我们考虑这种情况:

public interface RealPrincipal extends Principal {
   public Integer getId();
}

公共模块 A 具有 Real Principal 接口和实现。

Module A 使用 Common Module A,Servlet Api,不依赖 Spring Security:

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

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

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

public ModelAndView someRequestHandler(Principal principal) {
   User activeUser = (User) ((Authentication) principal).getPrincipal();
   ...
}

这迫使我对模块 A 和其他模块依赖 Spring Security。我相信一个适当的 servlet api 抽象不应该依赖于 spring 安全性。request.getUserPrincipal 应该返回真正的委托人。

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

身份验证而不是Real Principal.

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

4

2 回答 2

5

正如 Luke 所说,Spring Security 对 Principal 使用 Authentication,因为它实现了 Principal。它不使用 Authentication#getPrincipal() 因为它不能保证是 Principal (它是一个对象)。事实上,在大多数情况下,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);
    }
    ...
}

或者,查看我对您的其他问题的回答,了解与 Spring MVC 集成的选项 - Spring Security 将自定义主体注入控制器

于 2013-07-19T16:50:23.530 回答
1

简短的回答是AuthenticationPrincipal它可以用于需要一个的 API(例如您提到的 servlet API 方法)。

这在实践中意味着什么?不是很多。Java 的Principal接口只有一个方法getName,所以如果你想做的不仅仅是渲染用户名,你需要了解更多关于实现的知识。

当您使用短语“真正的主体”和“正确的 servlet api 抽象”时,您可能应该考虑一下您的意思。例如,如果委托人是“真正的”委托人,您希望如何实现您的someRequestHandler方法?

于 2013-07-19T11:04:20.820 回答