问题描述
我的项目包含两个不同的部分,一个JSF管理面板和一个RESTfull服务.我试图将spring security设置为根据用户导航的URL使用不同的身份验证方法.
My project consists exposes two different parts, a JSF admin panel and a RESTfull service.I am trying to setup spring security to use different authentication methods depending on the URL the user navigates.
要求是
- 导航到JSF页面的用户将获得一个登录屏幕,在此他们使用表单身份验证进行身份验证.
- 导航到REST服务的用户使用OAuth2隐式身份验证和用于令牌授予的基本身份验证.
单独的配置自行工作,问题是当我尝试将它们都组合成一个配置时,在那种情况下,即使请求提供给管理员,似乎REST提供程序也会妨碍并验证每个请求url(这是从Spring安全性命令中记录的.)
The seperate configurations work by themselves, the problem is when I try to combine both of them in one configuration, in that case it seems like the REST provider gets in the way and authenticates each request even if the requests go to the admin url (this is documented from spring security ordering).
我的示例配置如下所示:
My sample configurations are as shown:
-
用于表单登录(JSF)
For the form login (JSF)
@Override
@Order(1)
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.antMatchers("/templates/**").permitAll()
.antMatchers("/401.html").permitAll()
.antMatchers("/404.html").permitAll()
.antMatchers("/500.html").permitAll()
.antMatchers("/api/**").permitAll()
.antMatchers("/ui/admin.xhtml").hasAnyAuthority("admin", "ADMIN")
.antMatchers("/thymeleaf").hasAnyAuthority("admin", "ADMIN")
//.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/ui/index.xhtml")
.failureUrl("/login?error=1")
.permitAll()
.and()
.logout()
.permitAll()
.and()
.rememberMe()
.and().exceptionHandling().accessDeniedPage("/error/403");
OAuth2安全配置(REST)
OAuth2 security config (REST)
@EnableResourceServer
@Order(2)
public class RestSecurityConfig extends WebSecurityConfigurerAdapter {
@Inject
private UserRepository userRepository;
@Inject
private PasswordEncoder passwordEncoder;
@Bean
ApplicationListener<AbstractAuthorizationEvent> loggerBean() {
return new AuthenticationLoggerListener();
}
@Bean
AccessDeniedHandler accessDeniedHandler() {
return new AccessDeniedExceptionHandler();
}
@Bean
AuthenticationEntryPoint entryPointBean() {
return new UnauthorizedEntryPoint();
}
/*Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(
"/resources/**"
, "/templates/**"
, "/login"
, "/logout"
, "/ui/**"
, "/401.html"
, "/404.html"
, "/500.html"
);
}*/
@Override
protected void configure(HttpSecurity http) throws Exception {
ContentNegotiationStrategy contentNegotiationStrategy = http.getSharedObject(ContentNegotiationStrategy.class);
if (contentNegotiationStrategy == null) {
contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
}
MediaTypeRequestMatcher preferredMatcher = new MediaTypeRequestMatcher(contentNegotiationStrategy,
MediaType.APPLICATION_FORM_URLENCODED,
MediaType.APPLICATION_JSON,
MediaType.MULTIPART_FORM_DATA);
http.authorizeRequests()
.antMatchers("/ui/**").permitAll()
.and()
.anonymous().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().httpBasic()
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler()) // handle access denied in general (for example comming from @PreAuthorization
.authenticationEntryPoint(entryPointBean()) // handle authentication exceptions for unauthorized calls.
.defaultAuthenticationEntryPointFor(entryPointBean(), preferredMatcher)
.and()
.authorizeRequests()
.antMatchers("/api/**").fullyAuthenticated();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(new UserDetailsService() {
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User user = userRepository.findOneByUsername(s);
if (null == user) {
// leave that to be handled by log listener
throw new UsernameNotFoundException("The user with email " + s + " was not found");
}
return (UserDetails) user;
}
}).passwordEncoder(passwordEncoder);
}
@Configuration
@EnableAuthorizationServer
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
return new JwtAccessTokenConverter();
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("isAnonymous() || hasAuthority('ROLE_TRUSTED_CLIENT')").checkTokenAccess("hasAuthority('ROLE_TRUSTED_CLIENT')");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager).accessTokenConverter(accessTokenConverter());
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("xxx")
.resourceIds(xxx)
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes("read", "write", "trust", "update")
.accessTokenValiditySeconds(xxx)
.refreshTokenValiditySeconds(xxx)
.secret("xxx")
}
}
}
这些配置存在于不同的类中,并且顺序是手动设置的.
These configurations exist on different classes and the ordering is set manually.
有人对此问题有解决方案吗?
Has anyone any solutions to this issue?
最好
推荐答案
我尝试调整您的安全配置.不幸的是,由于缺少参考应用程序,我无法验证此配置.
I tried to adapt your security configuration. Unfortunately, I can not validate this configuration due to missing reference application.
也许可以帮助您:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserRepository userRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(new UserDetailsService() {
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User user = userRepository.findOneByUsername(s);
if (null == user) {
throw new UsernameNotFoundException("The user with email " + s + " was not found");
}
return (UserDetails) user;
}
}).passwordEncoder(passwordEncoder);
}
@Override
public void configure(WebSecurity webSecurity) throws Exception {
webSecurity
.ignoring()
.antMatchers("/resources/**"
, "/templates/**"
, "/login"
, "/logout"
, "/ui/**"
, "/401.html"
, "/404.html"
, "/500.html");
}
@Configuration
@EnableAuthorizationServer
public static class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
return new JwtAccessTokenConverter();
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("isAnonymous() || hasAuthority('ROLE_TRUSTED_CLIENT')").checkTokenAccess("hasAuthority('ROLE_TRUSTED_CLIENT')");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager).accessTokenConverter(accessTokenConverter());
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("xxx")
.resourceIds("xxx")
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes("read", "write", "trust", "update")
.accessTokenValiditySeconds(xxx)
.refreshTokenValiditySeconds(xxx)
.secret("xxx");
}
}
@Configuration
@Order(1)
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/ui/admin.xhtml").hasAnyAuthority("admin", "ADMIN")
.antMatchers("/thymeleaf").hasAnyAuthority("admin", "ADMIN")
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/ui/index.xhtml")
.failureUrl("/login?error=1")
.permitAll()
.and()
.logout()
.permitAll()
.and()
.rememberMe()
.and().exceptionHandling().accessDeniedPage("/error/403");
}
}
@Order(2)
@Configuration
@EnableResourceServer
public static class CustomResourceServerConfigurerAdapter extends ResourceServerConfigurerAdapter {
@Bean
ApplicationListener<AbstractAuthorizationEvent> loggerBean() {
return new AuthenticationLoggerListener();
}
@Bean
AccessDeniedHandler accessDeniedHandler() {
return new AccessDeniedExceptionHandler();
}
@Bean
AuthenticationEntryPoint entryPointBean() {
return new UnauthorizedEntryPoint();
}
@Override
public void configure(HttpSecurity http) throws Exception {
ContentNegotiationStrategy contentNegotiationStrategy = http.getSharedObject(ContentNegotiationStrategy.class);
if (contentNegotiationStrategy == null) {
contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
}
MediaTypeRequestMatcher preferredMatcher = new MediaTypeRequestMatcher(contentNegotiationStrategy,
MediaType.APPLICATION_FORM_URLENCODED,
MediaType.APPLICATION_JSON,
MediaType.MULTIPART_FORM_DATA);
http.authorizeRequests()
.and()
.anonymous().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().httpBasic()
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler()) // handle access denied in general (for example comming from @PreAuthorization
.authenticationEntryPoint(entryPointBean()) // handle authentication exceptions for unauthorized calls.
.defaultAuthenticationEntryPointFor(entryPointBean(), preferredMatcher)
.and()
.authorizeRequests()
.antMatchers("/api/**").fullyAuthenticated();
}
}
}
这篇关于Spring Security OAuth2和表单登录配置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!