您好,我有一个使用 Spring 安全性保护的 Web 应用程序,带有一个登录页面。这是我的安全配置
@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;
}
}
这可以很好地保护我的所有网络应用程序。
在同一个应用程序中,我还有一个资源/授权服务器来保护一些 REST api。
某些资源受到授权码授予的保护,因此不受信任的移动应用程序应使用登录表单从我的应用程序中获取访问 token 。我希望应用程序在尝试从移动应用程序登录时使用不同的登录页面。
这是我的资源服务器配置
@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);
}
}
所以,grantCredentialsConfiguration
应该将请求重定向到/apilogin 表单,但它没有,我被重定向到主 Web 应用程序登录页面...如何实现?
编辑
仔细查看日志,看起来当我尝试点击/oauth/authorize/时,正常的安全链发生了,我得到了
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.
所以它看起来像是在寻找一个处理程序来管理请求,而不是根据需要重定向到/api/apilogin,他发现了一个 Authentication exception
所以我转到标准登录页面.. . 但是为什么我会得到这个异常?
最佳答案
这是因为您没有指定安全配置类的顺序。
Spring中的安全资源保护应该从具体到通用。
类 SecurityConfiguration
比 grantCredentialsConfiguration
更通用。因为两者都保护以下资源。
- SecurityConfiguration 保护
/**
(Default URL) - grantCredentialsConfiguration
/api/oauth/**
由于没有定义顺序,SecurityConfiguration
的通用配置通过grantCredentialsConfiguration
要使这些按预期工作,您必须定义如下顺序。
@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 {
}
注意:由于这些登录页面不是来自不同的应用程序,它们共享 SecurityContextHolder
或安全上下文。因此,如果您从一个登录页面登录,然后尝试访问另一个登录页面的 protected 资源,您将不会被重定向到下一个登录页面。相反,您将获得 403(取决于不同登录页面分配的角色)。一次只能维护一个登录 session 。
这是 Github 上的示例
https://github.com/ConsciousObserver/TestMultipleLoginPages.git
关于java - Spring OAUTH - web e REST的不同登录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44001285/