Ser*_*gii 2 java configuration spring-mvc spring-security spring-boot
服务在可信空间中的网关之后工作(gateWay验证OAuth令牌并仅向服务提供唯一的用户ID,其他情况下它重定向以验证服务).
我想在服务中使用spring security来验证userId的权限.
所以我补充道 CustomUserDetailsService
@Service("userDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
@Autowired(required = false)
private ContextSsoActiveProfileIdProvider contextSsoActiveProfileIdProvider;
@Autowired
private GrantedAuthorityService grantedAuthorityService;
@Override
public User loadUserByUsername(final String username) throws UsernameNotFoundException {
// verify it with authentication service, but there is not token, userId only, so trust to gateway service.
return new User(
String.valueOf(contextSsoActiveProfileIdProvider.getSsoActiveProfileId()),
"authenticatedWithGateWay",
grantedAuthorityService.getGrantedAuthoritiesForCurrentUser()
);
}
}
其中contextSsoActiveProfileIdProvider.getSsoActiveProfileId()返回uniqueUserId和grantedAuthorityService.getGrantedAuthoritiesForCurrentUser()返回权限.
该服务在受信任区域中启动,因此我已在下一步配置安全性:
@EnableWebSecurity
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/**").permitAll();
}
@Override
protected UserDetailsService userDetailsService() {
return userDetailsService;
}
}
我需要为所有用户提供免费接入(不触发登录报价)所有的URI( http.authorizeRequests().antMatchers("/**").permitAll();),但它似乎抑制触发处理程序下一个注解@PreAuthorize,@PreFilter,@PostAuthorize和@PostFilter.
我想我在这里http.authorizeRequests().antMatchers("/**").permitAll();或与其他配置部分有误.
更多问题症状:
CustomUserDetailsService.loadUserByUsername(..) 永远不会被称为;@AuthenticationPrincipal User activeUser为nullPrincipal principal也是null可信空间问题与匿名用户识别有类似的解决方案(我在处理它时已经做了这个结论.)
受信任的空间并不需要授权,但没有一个UserDetailsService会被调用,因为只使用的,AnonymousAuthenticationProvider并且AnonymousAuthenticationFilter在默认情况下.基于AnonymousAuthenticationFilter覆盖createAuthentication并AnonymousAuthenticationFilter使用自定义one(CustomAnonymousAuthenticationFilter)替换default()是足够好的实现自定义过滤器:
@Configuration
public static class NoAuthConfigurationAdapter extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private IdentifiableAnonymousAuthenticationFilter identifiableAnonymousAuthenticationFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.anonymous().authenticationFilter(identifiableAnonymousAuthenticationFilter);
http.antMatcher("/**").authorizeRequests()
.anyRequest().permitAll();
}
}
我发现如果用户未经授权,将永远不会调用CustomUserDetailsService.持续研究关注AnonymousAuthenticationFilter,它负责创建匿名用户信息.因此,目的是用我的IdentifiableAnonymousAuthenticationFilter替换 AnonymousAuthenticationFilter,其中应该覆盖一些方法:
@Component
public class IdentifiableAnonymousAuthenticationFilter extends AnonymousAuthenticationFilter {
public static final String KEY_IDENTIFIABLE_ANONYMOUS_AUTHENTICATION_FILTER
= "Key.IdentifiableAnonymousAuthenticationFilter";
@Autowired
private CustomUserDetailsService userDetailsService;
@Autowired
private GrantedAuthorityService grantedAuthorityService;
private AuthenticationDetailsSource authenticationDetailsSource
= new WebAuthenticationDetailsSource();
public IdentifiableAnonymousAuthenticationFilter() {
this(KEY_IDENTIFIABLE_ANONYMOUS_AUTHENTICATION_FILTER);
}
public IdentifiableAnonymousAuthenticationFilter(String key) {
super(key);
}
@Override
protected Authentication createAuthentication(HttpServletRequest request) {
AnonymousAuthenticationToken auth = new AnonymousAuthenticationToken(
KEY_IDENTIFIABLE_ANONYMOUS_AUTHENTICATION_FILTER,
userDetailsService.loadCurrentUser(request),
grantedAuthorityService.getGrantedAuthoritiesForCurrentUser());
auth.setDetails(authenticationDetailsSource.buildDetails(request));
return auth;
}
}
将其注入配置中
@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
}
}
Run Code Online (Sandbox Code Playgroud)
现在看起来好多了,因为在AnonymousConfigurer中注入了identifiableAnonymousAuthenticationFilter.请注意基于的配置.如果你有几个,其中一个不会设置customAnonymousAuthenticationFilter但配置早于自定义..你将获得AnonymousAuthenticationFilter的默认实例(默认情况下配置):WebSecurityConfigurerAdapterWebSecurityConfigurerAdapter
protected final HttpSecurity getHttp() throws Exception {
//...
http
.csrf().and()
.addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling().and()
.headers().and()
.sessionManagement().and()
.securityContext().and()
.requestCache().and()
.anonymous().and()
// ...
如果应用程序已修复,我会关心它,但AnonymousAuthenticationFilter早于IdentifiableAnonymousAuthenticationFilter调用.而doFilter的付诸SecurityContextHolder中 incorrect的认证.
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);
}
Run Code Online (Sandbox Code Playgroud)
因此,当下次为IdentifiableAnonymousAuthenticationFilter调用doFilter时,它不会替换因为条件(请参阅之前的方法).Authenticationif(SecurityContextHolder.getContext().getAuthentication() == null)
因此,提供配置,WebSecurityConfigurerAdapter使用魔术注释@Order来管理配置加载顺序,可以提供配置.
或者有人会想 - doFilter在没有条件的情况下添加覆盖IdentifiableAnonymousAuthenticationFilter(它是黑客):
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
SecurityContextHolder.getContext().setAuthentication(createAuthentication((HttpServletRequest) req));
if (logger.isDebugEnabled()) {
logger.debug("Populated SecurityContextHolder with anonymous token: '"
+ SecurityContextHolder.getContext().getAuthentication() + "'");
}
chain.doFilter(req, res);
}
如果你需要处理授权/认证用户的弹簧安全性是不可接受的,但在某些情况下它就足够了.
解决方案的某些部分可以改进,但我希望这个想法一般都很明确.
| 归档时间: |
|
| 查看次数: |
874 次 |
| 最近记录: |