我尝试在基本Web应用程序中使用Java配置来配置Spring Security,以使用URL请求参数中提供的加密令牌对外部Web服务进行身份验证。
我希望(我认为)有一个安全过滤器来拦截来自Login Portal的请求(它们都进入/验证),过滤器将使用AuthenticationProvider来处理身份验证过程的业务逻辑。
登录门户 - >重定向' \ authenticate' (+令牌) - >将令牌验证回登录门户(WS) - >如果成功获得角色并设置用户。
我创建了一个过滤器..
@Component
public final class OEWebTokenFilter extends GenericFilterBean {
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
if (request instanceof HttpServletRequest) {
OEToken token = extractToken(request);
// dump token into security context (for authentication-provider to pick up)
SecurityContextHolder.getContext().setAuthentication(token);
}
}
chain.doFilter(request, response);
}
AuthenticationProvider ...
@Component
public final class OEWebTokenAuthenticationProvider implements AuthenticationProvider {
@Autowired
private WebTokenService webTokenService;
@Override
public boolean supports(final Class<?> authentication) {
return OEWebToken.class.isAssignableFrom(authentication);
}
@Override
public Authentication authenticate(final Authentication authentication) {
if (!(authentication instanceof OEWebToken)) {
throw new AuthenticationServiceException("expecting a OEWebToken, got " + authentication);
}
try {
// validate token locally
OEWebToken token = (OEWebToken) authentication;
checkAccessToken(token);
// validate token remotely
webTokenService.validateToken(token);
// obtain user info from the token
User userFromToken = webTokenService.obtainUserInfo(token);
// obtain the user from the db
User userFromDB = userDao.findByUserName(userFromToken.getUsername());
// validate the user status
checkUserStatus(userFromDB);
// update ncss db with values from OE
updateUserInDb(userFromToken, userFromDB);
// determine access rights
List<GrantedAuthority> roles = determineRoles(userFromDB);
// put account into security context (for controllers to use)
return new AuthenticatedAccount(userFromDB, roles);
} catch (AuthenticationException e) {
throw e;
} catch (Exception e) {
// stop non-AuthenticationExceptions. otherwise full stacktraces returned to the requester
throw new AuthenticationServiceException("Internal error occurred");
}
}
我的Spring Security Config
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
OESettings oeSettings;
@Bean(name="oeAuthenticationService")
public AuthenticationService oeAuthenticationService() throws AuthenticationServiceException {
return new AuthenticationServiceImpl(new OEAuthenticationServiceImpl(), oeSettings.getAuthenticateUrl(), oeSettings.getApplicationKey());
}
@Autowired
private OEWebTokenFilter tokenFilter;
@Autowired
private OEWebTokenAuthenticationProvider tokenAuthenticationProvider;
@Autowired
private OEWebTokenEntryPoint tokenEntryPoint;
@Bean(name="authenticationManager")
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(tokenAuthenticationProvider);
}
@Bean
public FilterRegistrationBean filterRegistrationBean () {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(tokenFilter);
registrationBean.setEnabled(false);
return registrationBean;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/authenticate**").permitAll()
.antMatchers("/resources/**").hasAuthority("ROLE_USER")
.antMatchers("/home**").hasAuthority("ROLE_USER")
.antMatchers("/personSearch**").hasAuthority("ROLE_ADMIN")
// Spring Boot actuator endpoints
.antMatchers("/autoconfig**").hasAuthority("ROLE_ADMIN")
.antMatchers("/beans**").hasAuthority("ROLE_ADMIN")
.antMatchers("/configprops**").hasAuthority("ROLE_ADMIN")
.antMatchers("/dump**").hasAuthority("ROLE_ADMIN")
.antMatchers("/env**").hasAuthority("ROLE_ADMIN")
.antMatchers("/health**").hasAuthority("ROLE_ADMIN")
.antMatchers("/info**").hasAuthority("ROLE_ADMIN")
.antMatchers("/mappings**").hasAuthority("ROLE_ADMIN")
.antMatchers("/metrics**").hasAuthority("ROLE_ADMIN")
.antMatchers("/trace**").hasAuthority("ROLE_ADMIN")
.and()
.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class)
.authenticationProvider(tokenAuthenticationProvider)
.antMatcher("/authenticate/**")
.exceptionHandling().authenticationEntryPoint(tokenEntryPoint)
.and()
.logout().logoutSuccessUrl(oeSettings.getUrl());
}
}
我的问题是我的SpringConfig类中的过滤器配置。我希望过滤器仅在请求用于/ authenticate URL时生效,我已将.antMatcher(&#34; / authenticate / **&#34;)添加到过滤器配置中。
.and()
.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class)
.authenticationProvider(tokenAuthenticationProvider)
.antMatcher("/authenticate/**")
.exceptionHandling().authenticationEntryPoint(tokenEntryPoint)
如果我的所有其他网址中的此行不再受到保护,我可以手动导航到/ home而不进行身份验证,删除该行并对/ home进行身份验证。
我是否应声明仅适用于特定网址的过滤器?
如何在保持其他网址安全的同时实现这一目标?
答案 0 :(得分:19)
我已经通过在使用身份验证提供程序之前检查过滤器中的身份验证状态来解决我的问题....
配置
.and()
.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class)
.authenticationProvider(tokenAuthenticationProvider)
.exceptionHandling().authenticationEntryPoint(tokenEntryPoint)
过滤
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
throws IOException, ServletException {
logger.debug(this + "received authentication request from " + request.getRemoteHost() + " to " + request.getLocalName());
if (request instanceof HttpServletRequest) {
if (isAuthenticationRequired()) {
// extract token from header
OEWebToken token = extractToken(request);
// dump token into security context (for authentication-provider to pick up)
SecurityContextHolder.getContext().setAuthentication(token);
} else {
logger.debug("session already contained valid Authentication - not checking again");
}
}
chain.doFilter(request, response);
}
private boolean isAuthenticationRequired() {
// apparently filters have to check this themselves. So make sure they have a proper AuthenticatedAccount in their session.
Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication();
if ((existingAuth == null) || !existingAuth.isAuthenticated()) {
return true;
}
if (!(existingAuth instanceof AuthenticatedAccount)) {
return true;
}
// current session already authenticated
return false;
}