我同时拥有:有效的spring-security
配置和有效的spring-oauth2
配置。两者都经过测试,并且可以单独正常工作。然后,我想添加oauth2作为用户的另一种身份验证方法。因此,用户可以选择要在我的服务中创建一个帐户,或者通过使用google或facebook帐户进行身份验证。
为此,我刚刚将工作ssoFilter
添加到http配置中:
.and().addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class)
这是我连接两种配置时的样子:
package com.fridayweekend.web.security.oauth2;
import com.fridayweekend.lottery.model.Authority;
import com.fridayweekend.lottery.model.User;
import com.fridayweekend.lottery.model.UserLoginType;
import com.fridayweekend.lottery.service.UserService;
import com.fridayweekend.web.security.CustomAuthFailureHandler;
import com.fridayweekend.web.security.CustomAuthSuccessHandler;
import com.fridayweekend.web.security.CustomAuthenticationProcessingFilterEntryPoint;
import com.fridayweekend.web.security.CustomLogoutSuccessHandler;
import com.fridayweekend.web.security.CustomPersistentTokenBasedRememberMeServices;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.oauth2.resource.AuthoritiesExtractor;
import org.springframework.boot.autoconfigure.security.oauth2.resource.PrincipalExtractor;
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
import org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter;
import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.common.AuthenticationScheme;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.web.filter.CompositeFilter;
import javax.servlet.Filter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.stream.Collectors;
@Configuration
@EnableWebSecurity
@EnableOAuth2Client
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MyWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
private static final Logger log = LoggerFactory.getLogger(MyWebSecurityConfigurerAdapter.class);
@Autowired
Properties myProperties;
@Autowired
UserService userService;
@Autowired
OAuth2ClientContext oauth2ClientContext;
@Autowired
UserDetailsService userDetailsService;
@Autowired
CustomLogoutSuccessHandler customLogoutSuccessHandler;
@Autowired
CustomPersistentTokenBasedRememberMeServices customPersistentTokenBasedRememberMeServices;
@Autowired
CustomAuthFailureHandler customAuthFailureHandler;
@Autowired
CustomAuthSuccessHandler customAuthSuccessHandler;
@Autowired
CustomAuthenticationProcessingFilterEntryPoint customAuthenticationProcessingFilterEntryPoint;
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception{
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
auth.authenticationProvider(provider);
}
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(customAuthenticationProcessingFilterEntryPoint)
.and()
.formLogin()
.loginPage("/login?now")
.failureHandler(customAuthFailureHandler)
.loginProcessingUrl("/user/j_spring_security_check")
.successHandler(customAuthSuccessHandler)
.and()
.logout()
.logoutUrl("/user/j_spring_security_logout")
.clearAuthentication(true)
.logoutSuccessHandler(customLogoutSuccessHandler)
.and()
.rememberMe()
.rememberMeServices(customPersistentTokenBasedRememberMeServices).key("myRememberMeKey")
.and()
.authorizeRequests()
.antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
.antMatchers("/moderator/**").access("hasRole('ROLE_MODERATOR')")
.antMatchers("/user/**").access("hasRole('ROLE_USER')")
.and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and().addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class)
;
}
@Bean
public FilterRegistrationBean oauth2ClientFilterRegistration(
OAuth2ClientContextFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(filter);
registration.setOrder(-100);
return registration;
}
@Bean
public ResourceServerProperties googleResource() {
ResourceServerProperties rsp = new ResourceServerProperties();
rsp.setUserInfoUri(myProperties.getProperty("google.resource.userInfoUri"));
rsp.setPreferTokenInfo(Boolean.parseBoolean(myProperties.getProperty("google.resource.preferTokenInfo")));
return rsp;
}
@Bean
public AuthorizationCodeResourceDetails google() {
AuthorizationCodeResourceDetails acrd = new AuthorizationCodeResourceDetails();
acrd.setClientId(myProperties.getProperty("google.client.clientId"));
acrd.setClientSecret(myProperties.getProperty("google.client.clientSecret"));
acrd.setAccessTokenUri(myProperties.getProperty("google.client.accessTokenUri"));
acrd.setUserAuthorizationUri(myProperties.getProperty("google.client.userAuthorizationUri"));
acrd.setTokenName(myProperties.getProperty("google.client.tokenName"));
acrd.setAuthenticationScheme(AuthenticationScheme.valueOf(myProperties.getProperty("google.client.authenticationScheme")));
acrd.setClientAuthenticationScheme(AuthenticationScheme.valueOf(myProperties.getProperty("google.client.clientAuthenticationScheme")));
acrd.setScope(Arrays.asList(myProperties.getProperty("google.client.scope")));
return acrd;
}
@Bean
public ResourceServerProperties facebookResource() {
ResourceServerProperties rsp = new ResourceServerProperties();
rsp.setUserInfoUri(myProperties.getProperty("facebook.resource.userInfoUri"));
return rsp;
}
@Bean
public AuthorizationCodeResourceDetails facebook() {
AuthorizationCodeResourceDetails acrd = new AuthorizationCodeResourceDetails();
acrd.setClientId(myProperties.getProperty("facebook.client.clientId"));
acrd.setClientSecret(myProperties.getProperty("facebook.client.clientSecret"));
acrd.setAccessTokenUri(myProperties.getProperty("facebook.client.accessTokenUri"));
acrd.setUserAuthorizationUri(myProperties.getProperty("facebook.client.userAuthorizationUri"));
acrd.setTokenName(myProperties.getProperty("facebook.client.tokenName"));
acrd.setAuthenticationScheme(AuthenticationScheme.valueOf(myProperties.getProperty("facebook.client.authenticationScheme")));
acrd.setClientAuthenticationScheme(AuthenticationScheme.valueOf(myProperties.getProperty("facebook.client.clientAuthenticationScheme")));
return acrd;
}
@Bean
public Filter ssoFilter() {
CompositeFilter filter = new CompositeFilter();
List<Filter> filters = new ArrayList<>();
String facebookLoginPath = "/login/facebook";
OAuth2ClientAuthenticationProcessingFilter facebookFilter = new OAuth2ClientAuthenticationProcessingFilter(facebookLoginPath);
OAuth2RestTemplate facebookTemplate = new OAuth2RestTemplate(facebook(), oauth2ClientContext);
facebookFilter.setRestTemplate(facebookTemplate);
UserInfoTokenServices tokenServices = new UserInfoTokenServices(facebookResource().getUserInfoUri(), facebook().getClientId());
PrincipalExtractor facebookPrincipalExtractor = principalExtractor(UserLoginType.FACEBOOK);
AuthoritiesExtractor facebookAuthoritiesExtractor = authoritiesExtractor();
tokenServices.setAuthoritiesExtractor(facebookAuthoritiesExtractor);
tokenServices.setPrincipalExtractor(facebookPrincipalExtractor);
tokenServices.setRestTemplate(facebookTemplate);
facebookFilter.setTokenServices(tokenServices);
filters.add(facebookFilter);
String googleLoginPath = "/login/google";
OAuth2ClientAuthenticationProcessingFilter googleFilter = new OAuth2ClientAuthenticationProcessingFilter(googleLoginPath);
OAuth2RestTemplate googleTemplate = new OAuth2RestTemplate(google(), oauth2ClientContext);
googleFilter.setRestTemplate(googleTemplate);
tokenServices = new UserInfoTokenServices(googleResource().getUserInfoUri(), google().getClientId());
PrincipalExtractor googlePrincipalExtractor = principalExtractor(UserLoginType.GOOGLE);
tokenServices.setPrincipalExtractor(googlePrincipalExtractor);
AuthoritiesExtractor googleAuthoritiesExtractor = authoritiesExtractor();
tokenServices.setAuthoritiesExtractor(googleAuthoritiesExtractor);
tokenServices.setRestTemplate(googleTemplate);
googleFilter.setTokenServices(tokenServices);
filters.add(googleFilter);
filter.setFilters(filters);
return filter;
}
private AuthoritiesExtractor authoritiesExtractor(){
return map -> {
String username = (String) map.get("id");
log.info("Setting roles for user {}", username);
User user = userService.getUserByName(username);
if (user == null) {
return Collections.<GrantedAuthority> emptyList();
}
List<Authority> authorities = user.getAuthorities();
List<String> roles = authorities.stream()
.map(Authority::getName)
.collect(Collectors.toList());
return AuthorityUtils.createAuthorityList(roles.stream().toArray(size -> new String[size]));
};
}
private PrincipalExtractor principalExtractor(UserLoginType type) {
return map -> {
String username = (String) map.get("id");
log.info("Searching for user {}", username);
User user = userService.getUserByName(username);
if (user == null) {
log.info("No user found, generating profile for {}", username);
user = new User();
user.setName(username);
user.setEmail((String) map.get("email"));
user.setDisplayName((String) map.get("name"));
userService.registerUser(user, null,null,null,null, type);
}
return user;
};
}
}
相关的web.xml
代码段:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/web-context.xml,
/WEB-INF/spring/web/wsServlet-context.xml,
/WEB-INF/spring/security/spring-security.xml
</param-value>
</context-param>
<!-- Spring Security -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>*</url-pattern>
</filter-mapping>
依赖版本:
<org.springframework-version>5.1.0.RELEASE</org.springframework-version>
<org.springframework.security-version>5.1.0.RELEASE</org.springframework.security-version>
<org.springboot-version>2.0.5.RELEASE</org.springboot-version>
<org.sringsecurity.security.oauth-version>2.3.3.RELEASE</org.sringsecurity.security.oauth-version>
<org.springframework.cloud.spring-cloud-security-version>2.0.0.RELEASE</org.springframework.cloud.spring-cloud-security-version>
<org.springframework.webflow-version>2.4.1.RELEASE</org.springframework.webflow-version>
<org.aspectj-version>1.7.3</org.aspectj-version>
<org.slf4j-version>1.6.1</org.slf4j-version>
<org.hibernate-version>5.3.6.Final</org.hibernate-version>
<spring.integration.version>4.1.4.RELEASE</spring.integration.version>
我做错什么了吗?我想念什么?
sring-security
配置有效(用户可以创建帐户/登录/注销),但是当他尝试访问URL login/facebook
或login/google
时,将引发以下异常并且不呈现页面完全没有:
0-Oct-2018 01:14:55.857 SEVERE [http-nio-8080-exec-6] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [entertainmentSelector] in context with path [] threw exception
org.springframework.security.oauth2.client.resource.UserRedirectRequiredException: A redirect is required to get the users approval
at org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.getRedirectForAuthorization(AuthorizationCodeAccessTokenProvider.java:359)
at org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.obtainAccessToken(AuthorizationCodeAccessTokenProvider.java:205)
at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainNewAccessTokenInternal(AccessTokenProviderChain.java:148)
at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainAccessToken(AccessTokenProviderChain.java:121)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:221)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173)
at org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.java:105)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:112)
at org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:73)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:668)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:770)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)