java - mkyong - Spring OAUTH-diferente inicio de sesión para web e REST
spring security oauth2 rest example (2)
¿Has intentado agregar URL path /apilogin
, al
.antMatchers("/", "/register", "/registrationConfirm",/resendRegistrationToken", "/park/**")
.permitAll()
Supongo que la aplicación está redirigiendo el acceso / apilogin a la página de inicio de sesión de autenticación común, ya que no se agrega a la lista de acceso no autenticado.
Hola, tengo una aplicación web asegurada con seguridad Spring, con una página de inicio de sesión. Esta es mi configuración de seguridad
@Configuration
@ComponentScan("it.besmart")
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
@Autowired
@Qualifier("customUserDetailsService")
UserDetailsService userDetailsService;
@Autowired
CustomSuccessHandler customSuccessHandler;
@Autowired
CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
@Autowired
DataSource dataSource;
@Autowired
private ConnectionFactoryLocator connectionFactoryLocator;
@Autowired
private UsersConnectionRepository usersConnectionRepository;
@Autowired
private FacebookConnectionSignup facebookConnectionSignup;
private final static Logger logger = LoggerFactory.getLogger(SecurityConfiguration.class);
@Autowired
public void configureGlobalService(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
protected void configure(HttpSecurity http) throws Exception {
logger.debug("Webapp security configured");
http.
authorizeRequests()
.antMatchers("/", "/register", "/registrationConfirm", "/resendRegistrationToken", "/park/**")
.permitAll()
.antMatchers("/edit/**", "/payment/**", "/plate/**", "/book/**", "/home", "/stop/**",
"/notification/**", "/include/**")
.access("hasRole(''USER'') or hasRole(''ADMIN'') or hasRole(''PARK'')").antMatchers("/admin/**")
.access("hasRole(''ADMIN'') or hasRole(''PARK'')").antMatchers("/updatePassword")
.hasAuthority("CHANGE_PASSWORD_PRIVILEGE")
.and().formLogin().loginPage("/")
.successHandler(customSuccessHandler).failureHandler(customAuthenticationFailureHandler)
.usernameParameter("email").passwordParameter("password").and().rememberMe()
.rememberMeParameter("remember-me").tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(86400).and().exceptionHandling().accessDeniedPage("/Access_Denied").and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/?logout=true").permitAll();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl db = new JdbcTokenRepositoryImpl();
db.setDataSource(dataSource);
return db;
}
}
Esto funciona bien asegurando toda mi aplicación web.
En la misma aplicación también tengo un servidor de recursos / autorización para proteger algunas API REST.
Algunos recursos están protegidos con una concesión de código de autorización, por lo que la aplicación móvil que no es de confianza debe tomar el token de acceso de mi aplicación con un formulario de inicio de sesión. Me gustaría que la aplicación utilice una página de inicio de sesión diferente al intentar iniciar sesión desde la aplicación móvil.
Esta es la configuración de mi resourceServer
@EnableResourceServer
@ComponentScan("it.besmart.easyparking")
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig {
private final Logger logger = LoggerFactory.getLogger(ResourceServerConfig.class);
@Autowired
DataSource dataSource;
private static final String RESOURCE_ID = "easyparking_api";
@Configuration
// @Order(2)
public class grantCredentialsConfiguration extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
logger.debug("Api security configured");
http
.requestMatchers().antMatchers("/api/oauth/**").and().authorizeRequests()
.antMatchers("/api/oauth/**").access("hasRole(''USER'')").and().formLogin().loginPage("/apilogin")
.permitAll();
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore()).resourceId(RESOURCE_ID);
}
}
@Configuration
// @Order(4)
public class clientCredentialsConfiguration extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
logger.debug("Client security configured");
http
.requestMatchers().antMatchers("/oauth2/**", "/api/registration", "/api/park/**").and()
.authorizeRequests().antMatchers("/oauth2/**", "/api/registration", "/api/park/**").authenticated();
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore()).resourceId(RESOURCE_ID);
}
}
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
}
entonces, grantCredentialsConfiguration
debe redirigir las solicitudes al formulario / apilogin, pero no es así, me redireccionan a la página principal de inicio de sesión de la aplicación web ... ¿Cómo se puede lograr?
EDITAR
Mirando más de cerca a los registros, parece que cuando trato de pulsar / oauth / authorize / la cadena de seguridad normal se lleva a cabo y obtengo
2017-05-25 12:23:15 DEBUG o.s.security.web.FilterChainProxy[310] - /oauth/authorize?response_type=token&client_id=test&redirect_uri=https://www.getpostman.com/oauth2/callback reached end of additional filter chain; proceeding with original chain
2017-05-25 12:23:15 DEBUG o.s.s.o.p.e.FrameworkEndpointHandlerMapping[310] - Looking up handler method for path /oauth/authorize
2017-05-25 12:23:15 DEBUG o.s.s.o.p.e.FrameworkEndpointHandlerMapping[317] - Returning handler method [public org.springframework.web.servlet.ModelAndView org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.authorize(java.util.Map<java.lang.String, java.lang.Object>,java.util.Map<java.lang.String, java.lang.String>,org.springframework.web.bind.support.SessionStatus,java.security.Principal)]
2017-05-25 12:23:15 DEBUG o.s.s.w.a.ExceptionTranslationFilter[163] - Authentication exception occurred; redirecting to authentication entry point
org.springframework.security.authentication.InsufficientAuthenticationException: User must be authenticated with Spring Security before authorization can be completed.
Parece que buscar un controlador para gestionar la solicitud, en lugar de redireccionar a / api / apilogin, encuentra una Authentication exception
y yo voy a la página de inicio de sesión estándar ... ¿Pero por qué me sale esta excepción?
Sucede porque no ha especificado el orden de las clases de configuración de seguridad.
En Spring, la protección de los recursos de seguridad se debe mencionar de específica a genérica.
Class SecurityConfiguration
es más genérica que grantCredentialsConfiguration
. Como ambos protegen los siguientes recursos.
- SecurityConfiguration protege
/**
( URL predeterminada ) - grantCredentialsConfiguration
/api/oauth/**
Como la orden no está definida, la configuración genérica de SecurityConfiguration
oculta la configuración específica mediante grantCredentialsConfiguration
Para que funcionen como se espera, tendrás que definir el orden de la siguiente manera.
@Configuration
@Order(2)//Generic config should have larger value (lower priority)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
}
@Configuration
@Order(1)//Specific with lower value (higher priority)
public class grantCredentialsConfiguration extends ResourceServerConfigurerAdapter {
}
Nota: Dado que estas páginas de inicio de sesión no provienen de diferentes aplicaciones, comparten SecurityContextHolder
o el contexto de seguridad. Por lo tanto, si inicia sesión desde una página de inicio de sesión y luego intenta acceder al recurso protegido de la otra, no será redirigido a la siguiente página de inicio de sesión. En cambio, obtendrá el 403 (dependiendo de los roles asignados por las diferentes páginas de inicio de sesión). En un momento, solo se puede mantener una sesión de inicio de sesión.
Aquí hay una muestra en Github
https://github.com/ConsciousObserver/TestMultipleLoginPages.git