#java #spring-boot #oauth-2.0 #jhipster #spring-security-oauth2
#java #spring-boot #oauth-2.0 #jhipster #spring-безопасность-oauth2
Вопрос:
В настоящее время я сталкиваюсь с проблемой обработки любых успешных и неудачных попыток входа в систему на моем сервере Spring Boot REST API.
Я хочу знать, вводит ли пользователь неправильную комбинацию логина / пароля для выполнения некоторого кода (изменения значения в базе данных). В настоящее время методы успешного / неудачного входа вообще не вызываются, но, как ни странно, выход из системы есть…
Для информации, когда я пытаюсь отправить неправильную комбинацию login, у меня есть это в журнале: Handling error: InvalidGrantException, Bad credentials
. Итак, возможно ли легко обработать это исключение InvalidGrantException? (в настоящее время мне нужно только отследить этот случай)
Любая помощь была бы высоко оценена!
Примечание: Проект использует OAuth 2 в качестве механизма входа, и я новичок в Spring Boot (исходя из Node.JS :p).
Заранее спасибо!
OAuth2ServerConfiguration
@Configuration
public class OAuth2ServerConfiguration {
@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Inject
private Http401UnauthorizedEntryPoint authenticationEntryPoint;
@Inject
private AjaxLogoutSuccessHandler ajaxLogoutSuccessHandler;
@Inject
private MyLoginSuccessHandler authenticationSuccessHandler;
@Inject
private MyLoginFailureHandler authenticationFailureHandler;
@Override
public void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.formLogin()
.loginPage("/oauth/token")
.successHandler(authenticationSuccessHandler) // Here is the handler for success login
.failureHandler(authenticationFailureHandler) // Here is the handler for failure login
.and()
.logout()
.logoutUrl("/api/logout")
.logoutSuccessHandler(ajaxLogoutSuccessHandler) // This handler works fine !
.and()
.csrf()
.disable()
.headers()
.frameOptions().disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/api/authenticate").permitAll()
.antMatchers("/api/register").permitAll();
}
}
}
MyLoginFailureHandler
@Component
public class MyLoginFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
LOG.info("CATCHING A LOGIN FAILURE !");
// Not called
// Here I want to know if the user enter wrong combinaison of login/password
}
}
@Component
public class MyLoginSuccessHandler implements AuthenticationSuccessHandler {
private static final Logger LOG = LoggerFactory.getLogger(MyLoginSuccessHandler.class);
public static final String BEARER_AUTHENTICATION = "Bearer ";
@Inject
private TokenStore tokenStore;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication)
throws IOException, ServletException {
LOG.info("CATCHING A LOGIN SUCCESS !");
// Not called
// Actually not usefull for me but not working too :/
}
}
======= ПРАВКА 1: =======
I tried to create a new handler specific for oAuth service but without success…
AuthorizationServerConfiguration
@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Inject
private DataSource dataSource;
@Inject
private JHipsterProperties jHipsterProperties;
@Inject
private OAuth2FailureHandler oAuth2FailureHandler; // Here is my handler
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
@Inject
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints
.tokenStore(tokenStore())
.authenticationManager(authenticationManager);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer
.allowFormAuthenticationForClients()
.accessDeniedHandler(oAuth2FailureHandler); // Setting up my handler here
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient(jHipsterProperties.getSecurity().getAuthentication().getOauth().getClientid())
.scopes("read", "write")
.authorities(AuthoritiesConstants.ADMIN, AuthoritiesConstants.USER)
.authorizedGrantTypes("password", "refresh_token", "authorization_code", "implicit")
.secret(jHipsterProperties.getSecurity().getAuthentication().getOauth().getSecret())
.accessTokenValiditySeconds(jHipsterProperties.getSecurity().getAuthentication().getOauth().getTokenValidityInSeconds());
}
}
OAuth2FailureHandler
@Component
public class OAuth2FailureHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
LOG.info("CATCHING A LOGIN FAILURE !");
// Not called
}
}
======= ПРАВКА 2: =======
Итак, я безуспешно попытался добавить фильтр в свою SecurityConfiguration.
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Inject
private UserDetailsService userDetailsService;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Inject
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**")
.antMatchers("/app/**/*.{js,html}")
.antMatchers("/bower_components/**")
.antMatchers("/i18n/**")
.antMatchers("/content/**")
.antMatchers("/swagger-ui/index.html")
.antMatchers("/api/register")
.antMatchers("/api/activate")
.antMatchers("/api/account/reset_password/init")
.antMatchers("/api/account/reset_password/finish")
.antMatchers("/test/**")
.antMatchers("/h2-console/**")
.antMatchers("/api/configuration");
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.httpBasic().realmName("xx")
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.requestMatchers().antMatchers("/oauth/authorize")
.and()
.authorizeRequests()
.antMatchers("/oauth/authorize").authenticated()
.and() // <---- I added this 2 lines of codes
.antMatcher("/**") // <-
.addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class); // <-
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}
// The new filter method
private Filter ssoFilter() {
OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter("/oauth/token");
filter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler() {
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
super.onAuthenticationSuccess(request, response, authentication);
QueryImpl.LOG.info("CATCHING A LOGIN SUCCESS !");
// Not called :(
}
});
return filter;
}
}
Комментарии:
1. Вы используете oauth, а не форму входа в систему. Следовательно, настройка обработчика успешного входа в систему на основе формы и ожидание, что он будет работать для oauth, очевидно, не сработает.
2. Спасибо за ваш ответ! Я попытался создать новый класс, реализующий AccessDeniedHandler (см. Мой отредактированный пост), но безуспешно.