1.微博配置文件:
#第三方微博登录配置
constants:
#WEIBO
weiBoAppId: ******(微博平台的AppID)
weiBoAppSecret: ********(微博平台的AppSecret)
weiBoRedirectUrl: ********(登录成功后的回调路径:http://www.****.com/api/v1/anon/weibo_login)
weiBoTokenUrl: https://api.weibo.com/oauth2/access_token(微博token路径)
weiBoUrl: https://api.weibo.com/oauth2/authorize? (访问微博路径)
weiBoOpenId: uid
clientId: ****-****-***-***-***** (客户端id)
url: http://uc.***.com (跳转首页,注册页的路径域名)
2.微博第三方登录:常量配置类
package com.ciip.cloud.core.usercenter.constants;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import javax.validation.constraints.NotEmpty;
/**
* Title: ThirdLoginConstants
* Description: 微博第三方登录:常量配置类
*
* @author
* @created 2019/5/7 14:10
*/
@Configuration
@ConfigurationProperties(prefix = "constants")
@Getter
@Setter
public class ThirdLoginConstants {
/**
* 微博的AppID
*/
@NotEmpty
private String weiBoAppId;
/**
* 微博的AppSecret
*/
@NotEmpty
private String weiBoAppSecret;
/**
* 微博的回调路径
*/
@NotEmpty
private String weiBoRedirectUrl;
/**
* 微博token路径
*/
@NotEmpty
private String weiBoTokenUrl;
/**
* 微博访问路径
*
*/
@NotEmpty
private String weiBoUrl;
/**
* 微博uid
*
*/
@NotEmpty
private String weiBoOpenId;
/**
* clientId
*
*/
@NotEmpty
private String clientId;
/**
* 域名路径
*
*/
@NotEmpty
private String url;
}
3.controller层:
package com.ciip.cloud.core.usercenter.controller;
/**
* Title: ThirdLoginController
* Description: 微博第三方登录
*
* @author
* @created 2019/5/14 10:57
*/
import com.ciip.cloud.core.common.constant.usercenter.CIIPCommonConstant;
import com.ciip.cloud.core.usercenter.service.WeiBoAuthService;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
@Api(value = "ThirdLoginController", description = "第三方登录(微信,QQ,微博)")
@RestController
@RequestMapping(value = CIIPCommonConstant.ApiPath.V1, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
public class ThirdLoginController {
@Autowired
WeiBoAuthService weiBoAuthService;
/**
* CIIP改版:微博登陆页面
* 2019-05-20
*
* @return
*/
@GetMapping(value = CIIPCommonConstant.ApiAuth.ANON +"/weibo_loginUrl")
public String getWeiBoCode(){
return weiBoAuthService.getWeiBoCode();
}
/**
* CIIP改版:微博获取token
* 2019-05-22
* @param code
* @param response
* @return
*/
@GetMapping(value = CIIPCommonConstant.ApiAuth.ANON +"/weibo_accessToken")
public String getWeiBoAccessToken(String code,HttpServletResponse response)throws Exception{
return weiBoAuthService.getWeiBoAccessToken(code,response);
}
}
4.service层:
package com.ciip.cloud.core.usercenter.service;
import javax.servlet.http.HttpServletResponse;
/**
* Title: WeiBoAuthService
* Description: 微博 认证接口
*
* @author
* @created 2019/5/20 17:30
*/
public interface WeiBoAuthService {
/**
* 获取WeiBoCode
* 2019-05-20
* @return
*/
String getWeiBoCode();
/**
* 获取WeiBoToken
* 2019-05-20
* @return
*/
String getWeiBoAccessToken(String code, HttpServletResponse response) throws Exception;
}
5.service实现层:
package com.ciip.cloud.core.usercenter.service.impl;
import cn.hutool.core.util.StrUtil;
import com.ciip.cloud.core.common.constant.enums.usercenter.CiipRegisterType;
import com.ciip.cloud.core.usercenter.constants.ThirdLoginConstants;
import com.ciip.cloud.core.usercenter.model.CiipTokenLog;
import com.ciip.cloud.core.usercenter.service.CiipTokenLogService;
import com.ciip.cloud.core.usercenter.service.WeiBoAuthService;
import com.ciip.cloud.core.usercenter.utils.HttpClientUtil;
import com.ciip.cloud.core.usercenter.utils.URLEncodeUtil;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.Date;
import static com.ciip.cloud.core.common.constant.usercenter.CIIPCommonConstant.OAUTH_LOGIN_URL.WEIBO_LOGIN;
import static org.springframework.security.oauth2.common.OAuth2AccessToken.ACCESS_TOKEN;
import static org.springframework.security.oauth2.common.OAuth2AccessToken.EXPIRES_IN;
/**
* Title: WeiBoAuthServiceImpl
* Description: 微博 实现层
*
* @author
* @created 2019/5/20 17:31
*/
@Service
public class WeiBoAuthServiceImpl implements WeiBoAuthService {
@Autowired
ThirdLoginConstants thirdLoginConstants;
@Autowired
CiipTokenLogService ciipTokenLogService;
/**
* 获取WeiBoCode
* 2019-05-20
* @return
*/
@Override
public String getWeiBoCode() {
//拼接url
StringBuilder url = new StringBuilder();
url.append(thirdLoginConstants.getWeiBoUrl());
url.append("client_id=").append(thirdLoginConstants.getWeiBoAppId());
//回调地址 ,回调地址要进行Encode转码
String redirect_uri = thirdLoginConstants.getWeiBoRedirectUrl();
//转码
url.append("&redirect_uri=").append(URLEncodeUtil.getURLEncoderString(redirect_uri));
url.append(WEIBO_LOGIN);
url.append("&response_type=code");
System.out.println(url.toString());
return url.toString();
}
/**
* 获取WeiBoToken
* 2019-05-20
*
* @return
*/
@Override
public String getWeiBoAccessToken(String code,HttpServletResponse response) throws Exception {
int expires_in;
String access_token = "";
String refresh_token = "";
String openid = "";
String params = "client_id=" + thirdLoginConstants.getWeiBoAppId()
+ "&client_secret=" + thirdLoginConstants.getWeiBoAppSecret()
+ "&grant_type=authorization_code"
+ "&redirect_uri=" + thirdLoginConstants.getWeiBoRedirectUrl()+WEIBO_LOGIN
+ "&code=" + code;
// 用code换取accessToken
String url = HttpClientUtil.postUrl(thirdLoginConstants.getWeiBoTokenUrl(), params);
//String url = HttpClientUtils.postParameters("https://api.weibo.com/oauth2/access_token", params);
JSONObject jsonObject = new JSONObject(url);
access_token = jsonObject.getString(ACCESS_TOKEN);
openid = jsonObject.getString(thirdLoginConstants.getWeiBoOpenId());
expires_in =(int)jsonObject.get(EXPIRES_IN);
//refresh_token = jsonObject.getString(REFRESH_TOKEN);
if(StrUtil.isNotEmpty(openid)){
//根据openid,获取token表信息
CiipTokenLog tokenLog = ciipTokenLogService.findBySourceId(openid);
if(null != tokenLog){
//token 信息的修改
tokenLog.setExpiresIn(expires_in);
tokenLog.setAccessToken(access_token);
tokenLog.setRefreshToken(refresh_token);
tokenLog.setModifyDate(new Date());
ciipTokenLogService.saveCiipTokenLog(tokenLog);
}else{
//token 信息的添加
CiipTokenLog ciipTokenLog = new CiipTokenLog();
ciipTokenLog.setAccessToken(access_token);
ciipTokenLog.setExpiresIn(expires_in);
ciipTokenLog.setRefreshToken(refresh_token);
ciipTokenLog.setOpenId(openid);
ciipTokenLog.setRegisterType(CiipRegisterType.weixin);
ciipTokenLog.setCreateDate(new Date());
ciipTokenLogService.saveCiipTokenLog(ciipTokenLog);
}
}
return openid;
}
}
6.安全配置(SecurityConfig):
package com.ciip.cloud.core.usercenter.oauth;
import com.ciip.cloud.core.usercenter.handler.CustomAccessDeniedHandler;
import com.ciip.cloud.core.usercenter.handler.CustomAuthenticationFailureHandler;
import com.ciip.cloud.core.usercenter.oauth.moblie.SmsAuthenticationConfig;
import com.ciip.cloud.core.usercenter.oauth.moblie.SmsCodeFilter;
import com.ciip.cloud.core.usercenter.oauth.qq.QQCodeFilter;
import com.ciip.cloud.core.usercenter.oauth.qq.QqAuthenticationConfig;
import com.ciip.cloud.core.usercenter.oauth.weiBo.WeiBoAuthenticationConfig;
import com.ciip.cloud.core.usercenter.oauth.weiBo.WeiBoCodeFilter;
import com.ciip.cloud.core.usercenter.oauth.weiXin.WeiXinAuthenticationConfig;
import com.ciip.cloud.core.usercenter.oauth.weiXin.WeiXinCodeFilter;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@Order(1)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsService userDetailsService;
@Autowired
CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
@Autowired
CustomAccessDeniedHandler customAccessDeniedHandler;
@Autowired
private SmsAuthenticationConfig smsAuthenticationConfig;
@Autowired
private QqAuthenticationConfig qqAuthenticationConfig;
@Autowired
private WeiXinAuthenticationConfig weiXinAuthenticationConfig;
@Autowired
private WeiBoAuthenticationConfig weiBoAuthenticationConfig;
@Autowired
private SmsCodeFilter smsCodeFilter;
@Autowired
private WeiXinCodeFilter weiXinCodeFilter;
@Autowired
private WeiBoCodeFilter weiBoCodeFilter;
@Autowired
private QQCodeFilter qqCodeFilter;
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception { // @formatter:off
http
// 头部缓存
.headers()
.cacheControl()
.and()
// 防止网站被人嵌套
.frameOptions()
.sameOrigin();
http
.addFilterBefore(smsCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加短信验证码校验过滤器
.addFilterBefore(weiXinCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加weixin验证码校验过滤器
.addFilterBefore(weiBoCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加weiBo验证码校验过滤器
.addFilterBefore(qqCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加QQ验证码校验过滤器
.formLogin().failureHandler(customAuthenticationFailureHandler).and()
.authorizeRequests() // 授权配置
.antMatchers("/login","/api/v1/anon/**","/oauth/authorize","/oauth/token").permitAll() // 无需认证的请求路径
// .anyRequest() // 所有请求
// .authenticated() // 都需要认证
.and()
.csrf().disable()
.apply(smsAuthenticationConfig)//短信验证
.and().apply(qqAuthenticationConfig) // 第三方QQ登录验证
.and().apply(weiXinAuthenticationConfig) // 第三方WeiXin登录验证
.and().apply(weiBoAuthenticationConfig); // 第三方微博登录验证
http.exceptionHandling().accessDeniedHandler(customAccessDeniedHandler);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception { // @formatter:off
auth.userDetailsService(userDetailsService).passwordEncoder(customPasswordEncoder());
} // @formatter:on
//TODO 为了符合原有BIM用户加密方式,所以自定义加密规则
@Bean
public PasswordEncoder customPasswordEncoder() {
return new PasswordEncoder() {
@Override
public String encode(CharSequence rawPassword) {
return DigestUtils.md5Hex(rawPassword.toString());
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return DigestUtils.md5Hex(rawPassword.toString()).equals(encodedPassword);
}
};
}
// //TODO 采用内置加密方式,存储数据库格式如:'{MD5}e10adc3949ba59abbe56e057f20f883e'
@Bean
PasswordEncoder passwordEncoder(){
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
}
7.微博身份验证配置:
package com.ciip.cloud.core.usercenter.oauth.weiBo;
import com.ciip.cloud.core.usercenter.handler.CustomAuthenticationFailureHandler;
import com.ciip.cloud.core.usercenter.service.CiipUserService;
import org.springframework.beans.factory.annotation.Autowired;
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.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;
/**
* Title: WeiBoAuthenticationConfig
* Description: TODO
*
* @author
* @created 2019-05-23
*/
@Component
public class WeiBoAuthenticationConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
@Autowired
CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
@Autowired
WeiBoLoginSuccessHandler weiBoLoginSuccessHandler;
@Autowired
private CiipUserService userService;
@Override
public void configure(HttpSecurity http) throws Exception {
WeiBoAuthenticationFilter weiBoAuthenticationFilter = new WeiBoAuthenticationFilter();
weiBoAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
weiBoAuthenticationFilter.setAuthenticationSuccessHandler(weiBoLoginSuccessHandler);
weiBoAuthenticationFilter.setAuthenticationFailureHandler(customAuthenticationFailureHandler);
WeiBoAuthenticationProvider weiBoAuthenticationProvider = new WeiBoAuthenticationProvider();
weiBoAuthenticationProvider.setUserService(userService);
http.authenticationProvider(weiBoAuthenticationProvider)
.addFilterAfter(weiBoAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
}
}
8.微博身份验证筛选器:(验证是否通过)
package com.ciip.cloud.core.usercenter.oauth.weiBo;
import com.ciip.cloud.core.common.constant.usercenter.AddableHttpRequest;
import com.ciip.cloud.core.common.constant.usercenter.CIIPCommonConstant;
import org.springframework.http.HttpMethod;
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 javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Title: WeiBoAuthenticationFilter
* Description: TODO
*
* @author
* @created 2019-05-23
*/
public class WeiBoAuthenticationFilter extends AbstractAuthenticationProcessingFilter{
private boolean postOnly = true;
public WeiBoAuthenticationFilter() {
super(new AntPathRequestMatcher(CIIPCommonConstant.OAUTH_LOGIN_URL.WEIBO_LOGIN, HttpMethod.POST.name()));
}
public Authentication attemptAuthentication(HttpServletRequest request,HttpServletResponse response) throws AuthenticationException {
if (postOnly && !request.getMethod().equals(HttpMethod.POST.name())) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
//获取openId
AddableHttpRequest addableHttpRequest = ((AddableHttpRequest) request);
String openId = addableHttpRequest.getParameter("openId");
//进行登录认证
WeiBoAuthenticationToken authRequest = new WeiBoAuthenticationToken(openId);
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
protected void setDetails(HttpServletRequest request, WeiBoAuthenticationToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}
public void setPostOnly(boolean postOnly) {
this.postOnly = postOnly;
}
}
9.微博身份验证提供程序:
package com.ciip.cloud.core.usercenter.oauth.weiBo;
import com.ciip.cloud.core.usercenter.service.CiipUserService;
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;
/**
* Title: WeiBoAuthenticationProvider
* Description: TODO
*
* @author
* @created 2019-05-23
*/
public class WeiBoAuthenticationProvider implements AuthenticationProvider {
private CiipUserService userService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
WeiBoAuthenticationToken authenticationToken = (WeiBoAuthenticationToken) authentication;
String openId =(String) authenticationToken.getPrincipal();
UserDetails userDetails = userService.findByWeiboId(openId);
if (userDetails == null)
throw new InternalAuthenticationServiceException("未找到与该微博对应的用户");
WeiBoAuthenticationToken authenticationResult = new WeiBoAuthenticationToken(userDetails, userDetails.getAuthorities());
authenticationResult.setDetails(authenticationToken.getDetails());
return authenticationResult;
}
@Override
public boolean supports(Class<?> aClass) {
return WeiBoAuthenticationToken.class.isAssignableFrom(aClass);
}
public CiipUserService getUserService() {
return userService;
}
public void setUserService(CiipUserService userService) {
this.userService = userService;
}
}
10.微博身份验证令牌:
package com.ciip.cloud.core.usercenter.oauth.weiBo;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;
import java.util.Collection;
/**
* Title: WeiBoAuthenticationToken
* Description: TODO
*
* @author
* @created 2019-05-23
*/
public class WeiBoAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
private final Object principal;
public WeiBoAuthenticationToken(Object openId) {
super(null);
this.principal = openId;
setAuthenticated(false);
}
public WeiBoAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
super.setAuthenticated(true);
}
public Object getPrincipal() {
return this.principal;
}
@Override
public Object getCredentials() {
return null;
}
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");
}
super.setAuthenticated(false);
}
@Override
public void eraseCredentials() {
super.eraseCredentials();
}
}
11.微博前置过滤器:
package com.ciip.cloud.core.usercenter.oauth.weiBo;
import com.alibaba.fastjson.JSON;
import com.ciip.cloud.core.common.constant.usercenter.AddableHttpRequest;
import com.ciip.cloud.core.common.constant.usercenter.CIIPCommonConstant;
import com.ciip.cloud.core.common.vo.ResultUtil;
import com.ciip.cloud.core.common.vo.usercenter.OauthCode;
import com.ciip.cloud.core.usercenter.exception.ValidateCodeException;
import com.ciip.cloud.core.usercenter.handler.CustomAuthenticationFailureHandler;
import com.ciip.cloud.core.usercenter.model.CiipUser;
import com.ciip.cloud.core.usercenter.service.CiipUserService;
import com.ciip.cloud.core.usercenter.service.WeiBoAuthService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Title: WeiBoCodeFilter
* Description: TODO
*
* @author
* @created 2019/5/24 9:37
*/
@Component
public class WeiBoCodeFilter extends OncePerRequestFilter {
@Autowired
private CustomAuthenticationFailureHandler authenticationFailureHandler;
@Autowired
private CiipUserService ciipUserService;
@Autowired
private WeiBoAuthService weiBoAuthService;
/**
* 过滤器
* 2019-05-24
*
* @param request
* @param response
* @param filterChain
* @throws ServletException
* @throws IOException
*/
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String openId ="";
if (StringUtils.equalsIgnoreCase(request.getContextPath()+ CIIPCommonConstant.OAUTH_LOGIN_URL.WEIBO_LOGIN, request.getRequestURI()) && StringUtils.equalsIgnoreCase(request.getMethod(), HttpMethod.POST.name())) {
//1.根据code,获取openId
String code = request.getParameter("code");
try {
openId = weiBoAuthService.getWeiBoAccessToken(code,response);
} catch (Exception e) {
e.printStackTrace();
}
//2.将openId放入request请求对象中
AddableHttpRequest wrappedRequest = new AddableHttpRequest(request);
wrappedRequest.addParameter("openId",openId);
//3.获取当前用户【登录用户】
CiipUser ciipUser = ciipUserService.getCurrent();
//4.不为空,表示为登录状态,用于绑定用户
if(null != ciipUser && ("".equals(ciipUser.getWeiboId()) || null == ciipUser.getWeiboId())){
//5.绑定前验证,根据openId,获取对象【防止一个微博绑定多个用户】
CiipUser ciipUserInfo = ciipUserService.findCiipUserByWeiboId(openId);
//不为空,表示该微信号已经绑定其他用户
if(null != ciipUserInfo){
response.sendRedirect(thirdLoginConstants.getUrl()+"/account/binding?status=false&name=weibo");
return;
}
ciipUser.setWeiboId(openId);
ciipUserService.addCiipUser(ciipUser);
//添加系统消息--微博绑定成功
CiipUserMessage ciipUserMessage = new CiipUserMessage();
Map<String,Object> paramsMap = new HashMap<String, Object>();
ciipUserMessage.setCreateDate(new Date());
ciipUserMessage.setSoruceId(ciipUser.getId());
ciipUserMessage.setCreateUserId(ciipUser.getId());
ciipUserMessage.setCreateUserName(ciipUser.getUsername());
ciipUserMessage.setReceiveUserId(ciipUser.getId());
ciipUserMessage.setMessageBusinessType(CiipMessageBusinessType.BINDING_WEIBO);
ciipUserMessage.setMessageType(CiipMessageType.SYSTEM);
ciipUserMessage.setMsgTitle("微博绑定成功");
ciipUserMessage.setMsgBody(StrUtil.format(CiipUserMessageTemplate.getOperationInfo(16),paramsMap));
ciipUserMessageService.addMessage(ciipUserMessage);
response.setHeader("Content-Type", "application/json;charset=UTF-8");
response.sendRedirect(thirdLoginConstants.getUrl()+"/account/binding");
//byte[] bytes = JSON.toJSONBytes(ResultUtil.error(OauthCode.BINDING_SUCCESS.getCode(), OauthCode.BINDING_SUCCESS.getMsg(), request.getHeader("referer")));
//response.getOutputStream().write(bytes);
return;
}else{
//为空,表示未登录,则登录前进行验证
try {
validateWeiBoCode(openId);
} catch (ValidateCodeException e) {
wrappedRequest.addParameter("type","weiboId");
authenticationFailureHandler.onAuthenticationFailure(wrappedRequest, response, e);
return;
}
}
filterChain.doFilter(wrappedRequest, response);
}else{
filterChain.doFilter(request,response);
}
}
private void validateWeiBoCode(String openId) throws ServletRequestBindingException, ValidateCodeException {
//根据openId,获取用户信息
UserDetails userDetails = ciipUserService.findByWeiboId(openId);
//表示该用户不存在,跳转到注册页面
if(null == userDetails){
throw new ValidateCodeException("该用户与微博没有绑定或该用户不存在.");
}
//登录成功后,修改上次登录时间
CiipUser ciipUser = ciipUserService.findCiipUserByWeiboId(openId);
if(ciipUser != null){
if(null != ciipUser.getLoginDate() && !"".equals(ciipUser.getLoginDate())){
ciipUser.setLastLoggedDate(ciipUser.getLoginDate());
}else{
ciipUser.setLastLoggedDate(new Date());
}
ciipUser.setLoginDate(new Date());
ciipUserRepository.saveAndFlush(ciipUser);
}
}
}
12.HttpServletRequestWrapper的封装,用户request中添加参数
package com.ciip.cloud.core.common.constant.usercenter;
/**
* Title: AddableHttpRequest
* Description: TODO
*
* @author
* @created 2019/5/28 15:12
*/
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.*;
public class AddableHttpRequest extends HttpServletRequestWrapper {
private HttpServletRequest wrapped;
private Map<String, String[]> parameterMap;
public AddableHttpRequest(HttpServletRequest wrapped) {
super(wrapped);
this.wrapped = wrapped;
}
public void addParameter(String name, String value) {
if (parameterMap == null) {
parameterMap = new HashMap<String, String[]>();
parameterMap.putAll(wrapped.getParameterMap());
}
String[] values = parameterMap.get(name);
if (values == null) {
values = new String[0];
}
List<String> list = new ArrayList<String>(values.length + 1);
list.addAll(Arrays.asList(values));
if(!"".equals(value)){
list.add(value);
}
parameterMap.put(name, list.toArray(new String[0]));
}
@Override
public String getParameter(String name) {
if (parameterMap == null) {
return wrapped.getParameter(name);
}
String[] strings = parameterMap.get(name);
if (strings != null) {
return strings[0];
}
return null;
}
@Override
public Map<String, String[]> getParameterMap() {
if (parameterMap == null) {
return wrapped.getParameterMap();
}
return Collections.unmodifiableMap(parameterMap);
}
@Override
public Enumeration<String> getParameterNames() {
if (parameterMap == null) {
return wrapped.getParameterNames();
}
return Collections.enumeration(parameterMap.keySet());
}
@Override
public String[] getParameterValues(String name) {
if (parameterMap == null) {
return wrapped.getParameterValues(name);
}
return parameterMap.get(name);
}
}
13.微博登录成功处理程序:
package com.ciip.cloud.core.usercenter.oauth.weiBo;
import cn.hutool.core.lang.Console;
import cn.hutool.core.map.MapUtil;
import com.ciip.cloud.core.common.constant.enums.usercenter.CiipOperationMethod;
import com.ciip.cloud.core.common.constant.enums.usercenter.CiipOperationRecordType;
import com.ciip.cloud.core.common.constant.usercenter.CIIPCommonConstant;
import com.ciip.cloud.core.common.vo.ResultUtil;
import com.ciip.cloud.core.common.vo.usercenter.OauthCode;
import com.ciip.cloud.core.usercenter.service.CiipUserOperationLogService;
import com.ciip.cloud.core.usercenter.service.CiipUserService;
import com.ciip.cloud.core.usercenter.vo.CiipUserInfo;
import com.ciip.cloud.core.usercenter.vo.UserInfo;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* Title: WeiBoLoginSuccessHandler
* Description: TODO
*
* @author
* @created 2019/5/8 18:01
*/
@Component
public class WeiBoLoginSuccessHandler implements AuthenticationSuccessHandler {
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
private AuthorizationServerTokenServices authorizationServerTokenServices;
@Autowired
private CiipUserOperationLogService ciipUserOperationLogService;
private String redirectUrl ="/";
@Autowired
private CiipUserService ciipUserService;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
try {
String clientId = request.getParameter("clientId");
ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
TokenRequest tokenRequest = new TokenRequest(MapUtil.newHashMap(), clientId, clientDetails.getScope(), "mobile");
OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);
OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);
OAuth2AccessToken oAuth2AccessToken = authorizationServerTokenServices.createAccessToken(oAuth2Authentication);
Console.log("获取token 成功:{}", oAuth2AccessToken.getValue());
UserInfo user =(UserInfo)authentication.getPrincipal();
CiipUserInfo ciipUserInfo = ciipUserService.getAuthUserInfo(Long.valueOf(user.getUserId()));
//用户日志添加操作记录
Map<String,Object> paramsMap = new HashMap<String,Object>();
paramsMap.put("currentUser", user.getUsername());
ciipUserOperationLogService.addUserOperationLog(Long.valueOf(user.getUserId()),String.valueOf(user.getUserId()), CiipOperationRecordType.WEB_LOGIN.name(), CiipOperationMethod.WEIBO_LOGIN.name(), 14,paramsMap);
//添加header认证信息
response.setHeader(CIIPCommonConstant.AUTHORIZATION_HEADER, String.format("%s %s", CIIPCommonConstant.BEARER_TOKEN_TYPE, oAuth2AccessToken.getValue().toString()));
request.getSession().setAttribute(CIIPCommonConstant.BEARER_TOKEN,oAuth2AccessToken.getValue().toString());
response.setHeader("Content-Type", "application/json;charset=UTF-8");
//该方法为实现单点登录
redisUtil.setWithExpireTime(CIIPCommonConstant.CIIP_AUTH,request.getSession().getId(), oAuth2AccessToken.getValue(),oAuth2AccessToken.getExpiresIn());
//登录成功返回到首页
response.sendRedirect(thirdLoginConstants.getUrl()+"/login");
} catch (IOException e) {
throw new BadCredentialsException(
"Failed to decode basic authentication token");
}
}
}
14.自定义身份验证失败处理程序:
package com.ciip.cloud.core.usercenter.handler;
import com.alibaba.fastjson.JSON;
import com.ciip.cloud.core.common.constant.usercenter.CIIPCommonConstant;
import com.ciip.cloud.core.common.vo.ResultUtil;
import com.ciip.cloud.core.common.vo.usercenter.OauthCode;
import com.ciip.cloud.core.usercenter.service.CiipLoginHistoryService;
import com.ciip.cloud.core.usercenter.service.CiipUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
@Component
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
private Logger log = LoggerFactory.getLogger(this.getClass());
private String failureUrl = "/signIn";
@Autowired
CiipUserService ciipUserService;
@Autowired
CiipLoginHistoryService ciipLoginHistoryService;
@Override
public void onAuthenticationFailure(HttpServletRequest request,HttpServletResponse response, AuthenticationException exception) throws IOException {
AddableHttpRequest addableHttpRequest = ((AddableHttpRequest) request);
String openId = addableHttpRequest.getParameter("openId");
String type = addableHttpRequest.getParameter("type");
response.setHeader("Content-Type", "application/json;charset=UTF-8");
log.info("--------------未绑定,经跳转到注册页面--------------");
log.info("--------------openId--------------"+openId);
log.info("--------------type--------------"+type);
//跳转到注册页面,并带openId参数用于注册时直接绑定微信账号,type参数是微信,QQ,微博类型
response.sendRedirect(thirdLoginConstants.getUrl()+"/register?id="+ EncryptUtil.encrypt(openId)+"&type="+type);
//byte[] bytes = JSON.toJSONBytes(ResultUtil.error(OauthCode.USERCENTER_OAUTH_LOGIN_ERROR.getCode(),OauthCode.USERCENTER_OAUTH_LOGIN_ERROR.getMsg()+""+exception.getMessage(), "/register?"+type+"="+ EncryptUtil.encrypt(openId)));//返回到注册页面
//response.getOutputStream().write(bytes);
}
}
15.验证异常:
package com.ciip.cloud.core.usercenter.exception;
import org.springframework.security.core.AuthenticationException;
/**
* Title: ValidateCodeException
* Description: TODO
*
* @author
* @created 2019/5/8 18:33
*/
public class ValidateCodeException extends AuthenticationException {
public ValidateCodeException(String message) {
super(message);
}
}