问题描述
可信空间问题具有与匿名用户标识类似的解决方案(在研究时,我已经得出了这个结论。)
简短答案
受信任的空间并不需要授权,但没有 一个UserDetailsService
会被调用,因为只使用的,AnonymousAuthenticationProvider
并且AnonymousAuthenticationFilter
在默认情况下。足以实现基于AnonymousAuthenticationFilter
覆盖的自定义过滤器,createAuthentication
并AnonymousAuthenticationFilter
用自定义一个(CustomAnonymousAuthenticationFilter
)替换默认值():
@组态
公共静态类NoAuthConfigurationAdapter扩展了WebSecurityConfigurerAdapter {
@Autowired
私人UserDetailsService userDetailsService;
@Autowired
私有IdentifiableAnonymousAuthenticationFilter identifiableAnonymousAuthenticationFilter;
@Override
受保护的void configure(HttpSecurity http)抛出异常{
http.anonymous()。authenticationFilter(identifiableAnonymousAuthenticationFilter);
http.antMatcher(“ / **”)。authorizeRequests()
.anyRequest()。permitAll();
}
}
完整答案
@零件
公共类IdentifiableAnonymousAuthenticationFilter扩展了AnonymousAuthenticationFilter {
公共静态最终字符串KEY_IDENTIFIABLE_ANONYMOUS_AUTHENTICATION_FILTER
=“ Key.IdentifiableAnonymousAuthenticationFilter”;
@Autowired
私人CustomUserDetailsService userDetailsService;
@Autowired
私有GrantedAuthorityService grantAuthorityService;
私有AuthenticationDetailsSource身份验证DetailsSource
= new WebAuthenticationDetailsSource();
public IdentifiableAnonymousAuthenticationFilter(){
这个(KEY_IDENTIFIABLE_ANONYMOUS_AUTHENTICATION_FILTER);
}
public IdentifiableAnonymousAuthenticationFilter(String key){
超级(密钥);
}
@Override
受保护的身份验证createAuthentication(HttpServletRequest请求){
AnonymousAuthenticationToken auth = new AnonymousAuthenticationToken(
KEY_IDENTIFIABLE_ANONYMOUS_AUTHENTICATION_FILTER,
userDetailsService.loadCurrentUser(request),
grantAuthorityService.getGrantedAuthoritiesForCurrentUser());
auth.setDetails(authenticationDetailsSource.buildDetails(request));
返回认证;
}
}
将其注入配置
@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
}
}
现在看起来好多了,因为 identifiableAnonymousAuthenticationFilter 已注入
。请注意基于的配置WebSecurityConfigurerAdapter
。如果您只有几个,并且其中一个不会设置customAnonymousAuthenticationFilter, 而是配置为早于 custom .., 您将获得AnonymousAuthenticationFilter的 默认实例(默认情况下配置WebSecurityConfigurerAdapter
):
受保护的最终HttpSecurity getHttp()引发异常{
// ...
http
.csrf()。and()
.addFilter(新的WebAsyncManagerIntegrationFilter())
.exceptionHandling()。and()
.headers()。and()
.sessionManagement()。和()
.securityContext()。and()
.requestCache()。and()
.anonymous()。和()
// ...
如果应用程序已修复,我不会在乎,但是 早于 调用。然后 doFilter 放入 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);
}
因此,下一次为 *Authentication``if(SecurityContextHolder.getContext().getAuthentication()
== null)
结果,提供配置非常有用,其中WebSecurityConfigurerAdapter
使用魔术批注 修复配置以管理配置加载顺序。
警告
或者有人会想- doFilter
在 添加无条件覆盖(这是 ):
@Override
公共无效doFilter(ServletRequest请求,ServletResponse资源,FilterChain链)
引发IOException,servletexception {
SecurityContextHolder.getContext()。setAuthentication(createAuthentication((HttpServletRequest)req));
如果(logger.isDebugEnabled()){
logger.debug(“带有匿名令牌的已填充SecurityContextHolder:”
+ SecurityContextHolder.getContext()。getAuthentication()+“'”);
}
chain.doFilter(req,res);
}
如果您需要通过处理授权的/已认证的用户来确保spring安全性,这是不可接受的,但是在某些情况下,这就足够了。
ps
解决方案的某些部分可以改进,但我希望这个想法总体上是明确的。
解决方法
服务在网关在受信任空间中运行之后(gateWay验证OAuth令牌,并仅向服务提供唯一的用户ID,否则它将重定向到身份验证服务)。
我想在服务中使用Spring Security来验证userId的权限。
所以我加了 CustomUserDetailsService
@Service(“ userDetailsService”)
公共类CustomUserDetailsService实现UserDetailsService {
@Autowired(必填=假)
私有ContextSsoActiveProfileIdProvider contextSsoActiveProfileIdProvider;
@Autowired
私有GrantedAuthorityService grantAuthorityService;
@Override
公共用户loadUserByUsername(最终字符串用户名)抛出UsernameNotFoundException {
//使用身份验证服务验证它,但没有令牌,仅用户ID,因此信任网关服务。
返回新用户(
String.valueOf(contextSsoActiveProfileIdProvider.getSsoActiveProfileId()),
“ authenticatedWithGateWay”,
allowedAuthorityService.getGrantedAuthoritiesForCurrentUser()
);
}
}
其中 contextSsoActiveProfileIdProvider.getSsoActiveProfileId() 返回uniqueUserId,
grantAuthorityService.getGrantedAuthoritiesForCurrentUser() 返回权限。
该服务在受信任区域中启动,因此我已通过以下方式配置了安全性:
@EnableWebSecurity
@组态
公共类SecurityConfiguration扩展了WebSecurityConfigurerAdapter {
@Autowired
私人UserDetailsService userDetailsService;
@Override
受保护的void configure(HttpSecurity http)抛出异常{
http
.authorizeRequests()
.antMatchers(“ / **”)。permitAll();
}
@Override
受保护的UserDetailsService userDetailsService(){
返回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