使用openId换取access_token功能完成

This commit is contained in:
winLsy
2018-01-21 14:39:19 +08:00
parent 5d1071d704
commit 22b069a0e9
7 changed files with 330 additions and 1 deletions
@@ -2,6 +2,7 @@ package com.micro.fast.security.app.config.authorization2;
import com.micro.fast.security.app.config.component.MsAuthenticationFailureHandler;
import com.micro.fast.security.app.config.component.MsAuthenticationSuccessHandler;
import com.micro.fast.security.app.social.OpenIdAuthenticationSecurityConfig;
import com.micro.fast.security.core.authentication.mobile.SmsCodeAuthenticationSecurityConfig;
import com.micro.fast.security.core.master.SecurityConstants;
import com.micro.fast.security.core.master.SecurityProperties;
@@ -45,6 +46,9 @@ public class AuthorizationResourceConfig extends ResourceServerConfigurerAdapter
@Autowired
private ValidateCodeRepository validateCodeRepository;
@Autowired
private OpenIdAuthenticationSecurityConfig openIdAuthenticationSecurityConfig;
@Override
public void configure(HttpSecurity http) throws Exception {
//创建自定义的验证码过滤器,填入身份认证失败处理对象
@@ -55,7 +59,7 @@ public class AuthorizationResourceConfig extends ResourceServerConfigurerAdapter
validateCodeFilter.afterPropertiesSet();
http
//添加自定义的验证码处理器,在用户密码校验过滤器之前
//添加自定义的验证码处理器,在用户密码校验过滤器的方式获取令牌之前
.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
//使用表单登录
.formLogin()
@@ -93,6 +97,9 @@ public class AuthorizationResourceConfig extends ResourceServerConfigurerAdapter
.and()
//应用springSocial的配置,在接收到特殊的请求的时候进行社交登录.例如 /auth/qq 其中/auth是默认的前缀,qq是providerId
.apply(springSocialConfigurer)
.and()
//openid
.apply(openIdAuthenticationSecurityConfig);
;
}
}
@@ -0,0 +1,98 @@
package com.micro.fast.security.app.social;
import com.micro.fast.security.core.master.SecurityConstants;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.Assert;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* openId登录身份认证过滤器
* @author lsy
*/
public class OpenIdAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
/**
* 从请求中获取openId的key
*/
private String openIdParameter = SecurityConstants.DEFAULT_PARAMETER_NAME_OPNEID;
/**
* 从请求中获取providerId的key
*/
private String providerIdParameter = SecurityConstants.DEFAULT_PARAMETER_NAME_PROVIDERID;
/**
* 是不是只处理post请求
*/
private boolean postOnly = true;
/**
* 对/authentication/openid路径的post请求进行身份登录操作
*/
public OpenIdAuthenticationFilter() {
super(new AntPathRequestMatcher(SecurityConstants.DEFAULT_LOGIN_PROCESS_URL_OPENID, "POST"));
}
/**
* 主要的身份认证方法
* @param request
* @param response
* @return
* @throws AuthenticationException
*/
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (this.postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
} else {
//获取请求中的mobile
String openid = this.obtainMobile(request);
if (openid == null) {
openid = "";
}
openid = openid.trim();
String providerId = request.getParameter(this.providerIdParameter);
if (providerId == null){
providerId = "";
}
providerId = providerId.trim();
OpenIdAuthenticationToken authRequest = new OpenIdAuthenticationToken(openid,providerId);
this.setDetails(request, authRequest);
//调用AuthenticationManager中的方法
return this.getAuthenticationManager().authenticate(authRequest);
}
}
/**
* 获取openId的方法
* @param request
* @return
*/
protected String obtainMobile(HttpServletRequest request) {
return request.getParameter(this.openIdParameter);
}
protected void setDetails(HttpServletRequest request, OpenIdAuthenticationToken authRequest) {
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
}
public void setOpenIdParameter(String openIdParameter) {
Assert.hasText(openIdParameter, "Username parameter must not be empty or null");
this.openIdParameter = openIdParameter;
}
public void setPostOnly(boolean postOnly) {
this.postOnly = postOnly;
}
public final String getOpenIdParameter() {
return this.openIdParameter;
}
}
@@ -0,0 +1,78 @@
package com.micro.fast.security.app.social;
import com.micro.fast.security.core.authentication.mobile.SmsCodeAuthenticationToken;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.social.connect.UsersConnectionRepository;
import org.springframework.social.security.SocialUserDetails;
import org.springframework.social.security.SocialUserDetailsService;
import java.util.HashSet;
import java.util.Set;
/**
* 进行openId的身份认证提供类
* @author lsy
*/
public class OpenIdAuthenticationProvider implements AuthenticationProvider {
private SocialUserDetailsService userDetailsService;
private UsersConnectionRepository usersConnectionRepository;
/**
* 返回经过验证的Authentication
* @param authentication
* @return
* @throws AuthenticationException
*/
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
OpenIdAuthenticationToken openIdAuthenticationToken = (OpenIdAuthenticationToken) authentication;
Set<String> providerUserIds = new HashSet<>();
String principal = (String)openIdAuthenticationToken.getPrincipal();
providerUserIds.add(principal);
Set<String> userIds = usersConnectionRepository.findUserIdsConnectedTo(openIdAuthenticationToken.getProviderId(), providerUserIds);
if (CollectionUtils.isEmpty(userIds) || userIds.size()!=1) {
throw new InternalAuthenticationServiceException("无法获取用户的信息");
}
String userId = userIds.iterator().next();
UserDetails socialUserDetails = userDetailsService.loadUserByUserId(userId);
if (socialUserDetails == null){
throw new InternalAuthenticationServiceException("无法获取用户的信息");
}
OpenIdAuthenticationToken openIdAuthenticationTokenResult = new OpenIdAuthenticationToken(socialUserDetails, socialUserDetails.getAuthorities());
openIdAuthenticationTokenResult.setDetails(openIdAuthenticationToken.getDetails());
return openIdAuthenticationTokenResult;
}
/**
* 这个类是不是支持传入的token的校验
* @param authenticate
* @return
*/
@Override
public boolean supports(Class<?> authenticate) {
return OpenIdAuthenticationToken.class.isAssignableFrom(authenticate);
}
public SocialUserDetailsService getUserDetailsService() {
return userDetailsService;
}
public void setUserDetailsService(SocialUserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
public UsersConnectionRepository getUsersConnectionRepository() {
return usersConnectionRepository;
}
public void setUsersConnectionRepository(UsersConnectionRepository usersConnectionRepository) {
this.usersConnectionRepository = usersConnectionRepository;
}
}
@@ -0,0 +1,57 @@
package com.micro.fast.security.app.social;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.social.connect.UsersConnectionRepository;
import org.springframework.social.security.SocialUserDetailsService;
import org.springframework.stereotype.Component;
/**
* @author lsy
* openId登录的配置类
*/
@Component
public class OpenIdAuthenticationSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain,HttpSecurity>{
@Autowired
@Qualifier("msAuthenticationSuccessHandler")
private AuthenticationSuccessHandler authenticationSuccessHandler;
@Autowired
@Qualifier("msAuthenticationFailureHandler")
private AuthenticationFailureHandler authenticationFailureHandler;
@Autowired
@Qualifier("msUserDetailsServiceImpl")
private SocialUserDetailsService userDetailsService ;
@Autowired
private UsersConnectionRepository usersConnectionRepository;
@Override
public void configure(HttpSecurity http) throws Exception {
OpenIdAuthenticationFilter OpenIdAuthenticationFilter = new OpenIdAuthenticationFilter();
//将短信验证码登录过滤器放入AuthenticationManager,方便后续调用
OpenIdAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
OpenIdAuthenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler);
OpenIdAuthenticationFilter.setAuthenticationFailureHandler(authenticationFailureHandler);
//将根据手机号获取用户信息的对象放入短信验证码的provider中
OpenIdAuthenticationProvider openIdAuthenticationProvider = new OpenIdAuthenticationProvider();
openIdAuthenticationProvider.setUserDetailsService(userDetailsService);
openIdAuthenticationProvider.setUsersConnectionRepository(usersConnectionRepository);
//将自定义的provider放入authenticaionManger管理的集合中去
http.authenticationProvider(openIdAuthenticationProvider)
//将自定义的过滤器添加到用户账号密码校验过滤器后面
.addFilterAfter(OpenIdAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
}
}
@@ -0,0 +1,74 @@
package com.micro.fast.security.app.social;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import java.util.Collection;
/**
* APP社交登陆中使用openId进行登录的token
* @author lsy
*/
public class OpenIdAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = 1L;
private final Object principal;
/**
* 服务提供商的id
*/
private String providerId;
/**
* 在没有进行身份认证的时候存储手机号
* @param openId openId
*/
public OpenIdAuthenticationToken(String openId,String providerId) {
super((Collection)null);
this.principal = openId;
this.providerId = providerId;
this.setAuthenticated(false);
}
/**
* @param principal
* @param authorities
*/
public OpenIdAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
super.setAuthenticated(true);
}
@Override
public Object getCredentials() {
return null;
}
@Override
public Object getPrincipal() {
return this.principal;
}
@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
if (isAuthenticated) {
throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
} else {
super.setAuthenticated(false);
}
}
@Override
public void eraseCredentials() {
super.eraseCredentials();
}
public String getProviderId() {
return providerId;
}
public void setProviderId(String providerId) {
this.providerId = providerId;
}
}
@@ -0,0 +1 @@
package com.micro.fast.security.app.social;
@@ -41,4 +41,18 @@ public interface SecurityConstants {
*/
String DEFAULT_SESSION_INVALID_URL = "/ms-session-invalid.html";
/**
* 获取openId的key
*/
String DEFAULT_PARAMETER_NAME_OPNEID = "openid";
/**
* 获取providerId的key
*/
String DEFAULT_PARAMETER_NAME_PROVIDERID = "providerId";
/**
* openID获取access_token的步骤
*/
String DEFAULT_LOGIN_PROCESS_URL_OPENID = "/authentication/openId";
}