使用Spring Security 4.02,任何人都可以帮助我提供一些提示,了解如何在使用多个UsernameNotFoundException
时从PreAuthenticatedAuthenticationProvider
处理AuthenticationProviders
,以便经过身份验证的请求具有正确的标头,但是未经授权,是否发送到特定的URL而不是表单登录页面?
让我进一步解释一下我正在尝试访问由代理后面的SSO保护的Web应用程序。并非所有通过SSO身份验证的用户都可以访问此应用。所以我需要考虑3种访问方案:
访问网站时的操作应为:
使用我当前的配置,方案1& 3似乎按预期工作。对于方案2,我尝试将RequestHeaderAuthenticationFilter#setExceptionIfHeaderMissing
设置为true和false。
如果setExceptionIfHeaderMissing=false
,则ExceptionTranslationFilter
处理经过身份验证/未经授权的请求,其中AccessDeniedException
被引发并且用户被重定向到表单登录页面。
如果setExceptionIfHeaderMissing=true
,经过身份验证/未经授权的请求会从PreAuthenticatedCredentialsNotFoundException
遇到AbstractPreAuthenticatedProcessingFilter.doAuthenticate
并返回HTTP 500。
所以我阅读并重新阅读了Spring Security参考和api文档并搜索了网页,但我无法弄清楚我需要做什么。我想我在某种程度上需要启用某种过滤器或处理程序来捕获带有重定向响应的PreAuthenticatedCredentialsNotFoundException
。但我似乎无法用可用的所有弹簧工具来实现这一目标。有人可以提供一些细节吗?非常感谢提前!!
这是我的配置:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final String AUTHENTICATION_HEADER_NAME = "PKE_SUBJECT";
@Autowired
CustomUserDetailsServiceImpl customUserDetailsServiceImpl;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(preAuthenticatedAuthenticationProvider());
auth.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
auth.userDetailsService(customUserDetailsServiceImpl);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().and()
.authorizeRequests()
.antMatchers("/javax.faces.resource/**", "/resources/**", "/templates/**", "/public/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/public/welcome.xhtml")
.and()
.addFilter(requestHeaderAuthenticationFilter());
}
@Bean PreAuthenticatedAuthenticationProvider preAuthenticatedAuthenticationProvider() throws Exception {
PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
provider.setPreAuthenticatedUserDetailsService(userDetailsServiceWrapper());
return provider;
}
@Bean
public RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter() throws Exception {
RequestHeaderAuthenticationFilter filter = new RequestHeaderAuthenticationFilter();
filter.setPrincipalRequestHeader(AUTHENTICATION_HEADER_NAME);
filter.setAuthenticationManager(authenticationManagerBean());
filter.setExceptionIfHeaderMissing(true);
return filter;
}
@Bean
public UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken>
userDetailsServiceWrapper() throws Exception {
UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken> wrapper
= new UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken>();
wrapper.setUserDetailsService(customUserDetailsServiceImpl);
return wrapper;
}
}
我的自定义UserDetailsService:
@Service("customUserDetailsService")
public class CustomUserDetailsServiceImpl implements UserDetailsService {
@Autowired
UserRepo userRepo;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserDetailDO userDetail = userRepo.getUserDetailById(username);
if(userDetail == null) {
throw new UsernameNotFoundException("user is not authorized for this application");
}
List<UserRoleDO> roles = userRepo.getRolesByUsername(username);
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
if(CollectionUtils.isNotEmpty(roles)) {
for(UserRoleDO role : roles) {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(role.getRole());
authorities.add(authority);
}
}
UserDetails user = new User(username, "N/A", authorities);
return user;
}
}
答案 0 :(得分:3)
我意识到我不需要处理异常。我所做的就是改变我对此的看法。我意识到即使customUserDetailsService找不到用户名,该请求仍然是经过身份验证的请求,因为SSO和代理服务器会信任请求对请求进行身份验证。
因此,我返回了带有空权限集合的org.springframework.security.core.userdetails.User,而不是返回UsernameNotFoundException。并且因为默认情况下RequestHeaderAuthenticationFilter.setExceptionIfHeaderMissing = false,所以不会抛出异常,然后将经过身份验证的请求传递给访问过滤器,在此过滤器中确定请求无权访问任何资源。因此,不是重定向到下一个身份验证过滤器(即表单登录提供程序),而是返回403 Access Denied http状态,然后我可以覆盖该状态以重定向到用户友好的错误页面。