为可信空间定制Spring Security
服务在可信空间中的网关之后工作(gateWayvalidationOAuth令牌并仅向服务提供唯一的用户ID,其他情况下它重定向以validation服务)。
我想在服务中使用spring security来validationuserId的权限。
所以我添加了CustomUserDetailsService
@Service( “的UserDetailsService”) 公共类CustomUserDetailsService实现UserDetailsService { @Autowired(required = false) private ContextSsoActiveProfileIdProvider contextSsoActiveProfileIdProvider; @Autowired private GrantedAuthorityService grantAuthorityService; @覆盖 public User loadUserByUsername(final String username)throws UsernameNotFoundException { //使用身份validation服务validation它,但没有令牌,仅限userId,因此信任网关服务。 返回新用户( 将String.valueOf(contextSsoActiveProfileIdProvider.getSsoActiveProfileId()), “authenticatedWithGateWay” grantedAuthorityService.getGrantedAuthoritiesForCurrentUser() ); } }
其中contextSsoActiveProfileIdProvider.getSsoActiveProfileId()返回uniqueUserId和grantedAuthorityService.getGrantedAuthoritiesForCurrentUser()返回权限。
该服务在受信任区域中启动,因此我已通过下一步方式配置安全性:
@EnableWebSecurity @组态 公共类SecurityConfiguration扩展了WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @覆盖 protected void configure(HttpSecurity http)抛出Exception { HTTP .authorizeRequests() .antMatchers( “/ **”)permitAll(); } @覆盖 protected UserDetailsService userDetailsService(){ return userDetailsService; } }
我需要为所有URI( http.authorizeRequests().antMatchers("/**").permitAll();
)提供所有用户的免费访问权限(不触发登录提供),但似乎禁止触发下一个注释@PreAuthorize
处理程序, @PreFilter
, @PostAuthorize
和@PostFilter
。
我想我在这里误解了http.authorizeRequests().antMatchers("/**").permitAll();
或与其他配置部分。
更多问题症状:
- 从不调用
CustomUserDetailsService.loadUserByUsername(..)
; - 在REST API部分
@AuthenticationPrincipal User activeUser
为null - 在REST API部分,
Principal principal
也为null
可信空间问题与匿名用户识别有类似的解决方案(我在处理它时已经做了这个结论。)
简短的回答
可信空间不需要授权,但不会调用UserDetailsService ,因为默认情况下仅使用AnonymousAuthenticationProvider
和AnonymousAuthenticationFilter
。 基于AnonymousAuthenticationFilter
覆盖createAuthentication
并使用自定义( CustomAnonymousAuthenticationFilter
)替换默认( AnonymousAuthenticationFilter
)是很好的实现自定义filter:
@组态 public static class NoAuthConfigurationAdapter扩展WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Autowired private IdentifiableAnonymousAuthenticationFilter identifiableAnonymousAuthenticationFilter; @覆盖 protected void configure(HttpSecurity http)抛出Exception { http.anonymous()authenticationFilter(identifiableAnonymousAuthenticationFilter)。 http.antMatcher( “/ **”)。authorizeRequests() .anyRequest()permitAll(); } }
完整答案
我发现如果用户未经授权,将永远不会调用CustomUserDetailsService 。 持续研究注意AnonymousAuthenticationFilter ,它负责创建匿名用户信息。 因此,目的是用我的IdentifiableAnonymousAuthenticationFilter替换AnonymousAuthenticationFilter ,其中应该覆盖一些方法:
@零件 public class IdentifiableAnonymousAuthenticationFilter extends AnonymousAuthenticationFilter { public static final String KEY_IDENTIFIABLE_ANONYMOUS_AUTHENTICATION_FILTER =“Key.IdentifiableAnonymousAuthenticationFilter”; @Autowired private CustomUserDetailsService userDetailsService; @Autowired private GrantedAuthorityService grantAuthorityService; private AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource(); public IdentifiableAnonymousAuthenticationFilter(){ 此(KEY_IDENTIFIABLE_ANONYMOUS_AUTHENTICATION_FILTER); } public IdentifiableAnonymousAuthenticationFilter(String key){ 超级(键); } @覆盖 protected Authentication createAuthentication(HttpServletRequest request){ AnonymousAuthenticationToken auth = new AnonymousAuthenticationToken( KEY_IDENTIFIABLE_ANONYMOUS_AUTHENTICATION_FILTER, userDetailsService.loadCurrentUser(请求), grantedAuthorityService.getGrantedAuthoritiesForCurrentUser()); auth.setDetails(authenticationDetailsSource.buildDetails(请求)); 返回认证; } }
将其注入配置中
@Configuration public class IdentifyAnonymousConfigurationAdapter extends WebSecurityConfigurerAdapter { @Autowired private IdentifiableAnonymousAuthenticationFilter identifiableAnonymousAuthenticationFilter; @Override protected void configure(HttpSecurity http) throws Exception { http.anonymous().authenticationFilter(identifiableAnonymousAuthenticationFilter); // ... some other configurations } }
现在看起来好多了,因为在AnonymousConfigurer中注入了identifiableAnonymousAuthenticationFilter 。 请注意基于WebSecurityConfigurerAdapter
的配置。 如果你有几个,其中一个不会设置customAnonymousAuthenticationFilter但配置早于自定义..你将获得AnonymousAuthenticationFilter的默认实例(默认情况下在WebSecurityConfigurerAdapter
配置):
protected final HttpSecurity getHttp()抛出Exception { // ... HTTP .csrf()和() .addFilter(new WebAsyncManagerIntegrationFilter()) .exceptionHandling()和() .headers()和() .sessionManagement()和() .securityContext()和() .requestCache()和() .anonymous()和() // ...
如果应用程序已修复,我会关心它,但AnonymousAuthenticationFilter早于IdentifiableAnonymousAuthenticationFilter调用。 并且doFilter将SecurityContextHolder放入incorrect
身份validation中。
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { if(SecurityContextHolder.getContext().getAuthentication() == null) { SecurityContextHolder.getContext().setAuthentication(this.createAuthentication((HttpServletRequest)req)); if(this.logger.isDebugEnabled()) { this.logger.debug("Populated SecurityContextHolder with anonymous token: '" + SecurityContextHolder.getContext().getAuthentication() + "'"); } } else if(this.logger.isDebugEnabled()) { this.logger.debug("SecurityContextHolder not populated with anonymous token, as it already contained: '" + SecurityContextHolder.getContext().getAuthentication() + "'"); } chain.doFilter(req, res); }
因此,当下次为IdentifiableAnonymousAuthenticationFilter调用doFilter时,由于条件if(SecurityContextHolder.getContext().getAuthentication() == null)
它不会替换Authentication
if(SecurityContextHolder.getContext().getAuthentication() == null)
(请参阅之前的方法)。
因此,使用魔术注释@Order管理配置加载顺序来修复WebSecurityConfigurerAdapter
配置的配置非常好。
警告
或者有人会想 – 在没有条件的情况下添加doFilter
覆盖IdentifiableAnonymousAuthenticationFilter (它是黑客 ):
@覆盖 public void doFilter(ServletRequest req,ServletResponse res,FilterChain chain) 抛出IOException,ServletException { SecurityContextHolder.getContext()。setAuthentication(createAuthentication((HttpServletRequest)req)); if(logger.isDebugEnabled()){ logger.debug(“带有匿名标记的填充SecurityContextHolder:'” + SecurityContextHolder.getContext()。getAuthentication()+“'”); } chain.doFilter(req,res); }
如果你需要处理授权/认证用户的弹簧安全性是不可接受的,但在某些情况下它就足够了。
PS
解决方案的某些部分可以改进,但我希望这个想法一般都很明确。