gpt4 book ai didi

spring-mvc - Spring 安全 : Why is my custom AccessDecisionVoter not invoked

转载 作者:行者123 更新时间:2023-12-03 20:28:38 25 4
gpt4 key购买 nike

我正在尝试使用自定义 AccessDecisionVoter 进行 URL 授权。我没有收到任何错误,调试显示我的选民在启动时被选中。但是,在运行时,不会调用 vote 方法,因此允许每个经过身份验证的用户完全访问。

请注意,我不需要方法安全性。我也没有使用 XML 配置。这排除了互联网上发布的关于该主题的所有示例。

@Configuration
@EnableWebSecurity
@EnableWebMvc
@ComponentScan
@Order(-10)
public class HttpSecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${trusted_ports}")
private List<Integer> trustedPorts;

@Autowired
private UserDetailsService userDetailsService;

@Autowired
private ServiceIdAwareVoter serviceIdAwareVoter;

RequestMatcher requestMatcher = new OrRequestMatcher(
// @formatter:off
new AntPathRequestMatcher("/**", GET.name()),
new AntPathRequestMatcher("/**", POST.name()),
new AntPathRequestMatcher("/**", DELETE.name()),
new AntPathRequestMatcher("/**", PATCH.name()),
new AntPathRequestMatcher("/**", PUT.name())
// @formatter:on
);

@Override
protected UserDetailsService userDetailsService() {
return userDetailsService;
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(preAuthProvider());
auth.authenticationProvider(authProvider());
}

@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.
httpBasic().and().
authorizeRequests().anyRequest().fullyAuthenticated().
accessDecisionManager(accessDecisionManager()).and().
csrf().disable().
logout().disable().
exceptionHandling().and().
sessionManagement().sessionCreationPolicy(STATELESS).and().
anonymous().disable().
addFilterAfter(preAuthFilter(), X509AuthenticationFilter.class).
addFilter(authFilter());
// @formatter:on
}

AccessDecisionManager accessDecisionManager() {
return new UnanimousBased(ImmutableList.of(serviceIdAwareVoter));
}

Filter preAuthFilter() throws Exception {
PreAuthenticationFilter preAuthFilter = new PreAuthenticationFilter(trustedPorts);

preAuthFilter.setAuthenticationManager(super.authenticationManager());

return preAuthFilter;
}

PreAuthenticatedAuthenticationProvider preAuthProvider() {
PreAuthenticatedAuthenticationProvider preAuthProvider = new PreAuthenticatedAuthenticationProvider();
UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken> userDetailsServiceWrapper = new UserDetailsByNameServiceWrapper<>();

userDetailsServiceWrapper.setUserDetailsService(userDetailsService());

preAuthProvider.setPreAuthenticatedUserDetailsService(userDetailsServiceWrapper);

return preAuthProvider;
}

Filter authFilter() throws Exception {
AppIdAppKeyAuthenticationFilter authFilter = new AppIdAppKeyAuthenticationFilter(requestMatcher);
authFilter.setAuthenticationFailureHandler(new ExceptionStoringAuthenticationFailureHandler());
authFilter.setAuthenticationSuccessHandler(new UrlForwardingAuthenticationSuccessHandler());

authFilter.setAuthenticationManager(authenticationManagerBean());

return authFilter;
}

AuthenticationProvider authProvider() {
AppIdAppKeyAuthenticationProvider authProvider = new AppIdAppKeyAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService());

return authProvider;
}

最佳答案

背景:

经过几个小时的调试,才找出问题的根源,真是深奥。部分原因是 Spring Security Java 配置的文档非常少(为此我打开了 JIRA ticket )。他们的以及大多数在线示例都是从 XML 配置复制粘贴的,而世界可能从 2010 年开始就停止使用 Spring XML 配置。另一部分是由于 REST 服务安全性是 Spring Security 设计中的事后考虑,他们没有一流的支持来保护没有登录页面、错误页面和普通 View 层的应用程序。最后但并非最不重要的一点是,我的应用程序中有几个(错误的)配置,它们全部结合在一起,形成了一场令人难以置信的复杂性的完美 Storm 。

技术背景:

使用 authorizeRequests() 配置一个 ExpressionUrlAuthorizationConfigurer 最终设置一个 UnanimousBased AccessDecisionManager 和一个 WebExpressionVoter。如果身份验证成功,则从 FilterSecurityInterceptor 调用此 AccessDecisionManager(显然,如果用户首先未通过身份验证,则授权没有意义)。

问题:

  • 在我的 AbstractAnnotationConfigDispatcherServletInitializer 子类(基本上是 web.xml 的 Java 版本)中,我将过滤器配置为不拦截转发请求。我不打算在这里讨论为什么。对于感兴趣的,这里有一个如何完成的例子:

    private Dynamic registerCorsFilter(ServletContext ctx) {
    Dynamic registration = ctx.addFilter("CorsFilter", CorsFilter.class);

    registration.addMappingForUrlPatterns(getDispatcherTypes(), false, "/*");
    return registration;
    }

    private EnumSet<DispatcherType> getDispatcherTypes() {
    return (isAsyncSupported() ? EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.ASYNC)
    : EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE));
    }

如果您将 DispatcherType.FORWARD 从调度程序类型集中取出,则已注册的过滤器不会针对此类请求启动。

  • 我的问题中显示的 authFilterUsernamePasswordAuthenticationFilter 扩展而来,并且有一个 AuthenticationSuccessHandler,它在成功验证后将请求转发到目标 URL。默认的 Spring 实现使用 SavedRequestAwareAuthenticationSuccessHandler 重定向到网页,这在 REST 应用程序的上下文中是不需要的。
  • 由于上述 2 个原因,FilterSecurityInterceptor 在成功验证后未被调用,这反过来又跳过了导致我原始帖子中的问题的授权链。

修复:

  • 从 Web 应用初始化程序中删除自定义调度程序配置。
  • 不要从 AuthenticationSuccessHandler 转发或重定向。让请求顺其自然。
  • 自定义投票器有一个 vote 方法,如下所示:

    public int vote(Authentication authentication, FilterInvocation fi,
    Collection<ConfigAttribute> attributes) {
    }

在我的例子中,属性,如我原来的帖子所示,是字符串表达式fullyAuthenticated。我没有使用它进行授权,因为我已经知道用户已经通过身份验证流程中的各种过滤器进行了身份验证。

我希望这可以作为所有因 Spring Security Java 配置中缺乏文档而受苦的灵魂的文档。

关于spring-mvc - Spring 安全 : Why is my custom AccessDecisionVoter not invoked,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34552926/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com