Я пытаюсь настроить Spring Безопасность с помощью конфигурации Java в базовом веб-приложении для проверки подлинности на внешней веб-службе с использованием зашифрованного токена, предоставленного в параметре запроса URL-адреса.
Я бы хотел (я думаю) иметь фильтр безопасности, который перехватывает запросы из портала входа (все они идут/аутентифицируются), фильтр будет использовать AuthenticationProvider для обработки логики бизнес-процесса аутентификации.
Login Portal → Redirect '\ authenticate' (+ Token) → Аутентификация маркера обратно на портал входа в систему (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);
}
Провайдер аутентификации...
@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 Конфигурация безопасности
@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. Я хочу, чтобы фильтр только вступал в силу, когда запрос предназначен для/аутентификации URL, я добавил .antMatcher( "/authenticate/**" ) в конфигурацию фильтра.
.and()
.addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class)
.authenticationProvider(tokenAuthenticationProvider)
.antMatcher("/authenticate/**")
.exceptionHandling().authenticationEntryPoint(tokenEntryPoint)
Когда у меня эта строка во всех других URL-адресах больше не защищена, я могу вручную перейти в /home без проверки подлинности, удалить строку и /home пройти аутентификацию.
Должен ли я объявлять фильтр, который применим только к определенному URL?
Как я могу реализовать это, сохраняя безопасность других URL-адресов?