1、新增依赖

<dependency>
<groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId>
<version>1.16.5</version>
</dependency>

2、前端示例

<template>
<div class="social-signup-container">
<div class="sign-btn" @click="thirdLoginClick('wechat')">
<span class="wx-svg-container"><svg-icon icon-class="wechat" class="icon"/></span>
微信
</div>
<div class="sign-btn" @click="thirdLoginClick('qq')">
<span class="qq-svg-container"><svg-icon icon-class="qq" class="icon"/></span>
QQ
</div>
<div class="sign-btn" @click="thirdLoginClick('gitee')">
<span class="gitee-svg-container"><svg-icon icon-class="gitee" class="icon"/></span>
Gitee
</div>
</div>
</template>
<script>
export default {
name: 'SocialSignin',
methods: {
   // 请求后台获取跳转路径
thirdLoginClick(source) {
this.$store.dispatch('user/thirdLogin', {source: source}).then(() => {
}).catch(() => {
})
}
}
}
</script>
  // 第三方登录
thirdLogin({commit}, userInfo) {
const {source} = userInfo
return new Promise((resolve, reject) => {
thirdLogin({source: source.trim()}).then(response => {
console.log("第三方登录返回", response)
if (response.data.code === "200") {
window.location.href = response.data.url
} else {
Message.warning(response.data.msg);
}
resolve()
}).catch(error => {
reject(error)
})
})
}
export function thirdLogin(data) {
return request({
url: '/login/render',
method: 'post',
params: {source: data.source}
})
}

3、后端示例

获取跳转路径
import com.mxy.common.core.utils.ServiceResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.springframework.web.bind.annotation.*; import javax.annotation.Resource;
import java.util.*; /**
* 第三方登录认证
*/
@RestController
@RequestMapping("/api/login")
@Api(value = "第三方登录相关接口", tags = {"第三方登录相关接口"})
@Slf4j
public class AuthRestApi { @Resource
private AuthUtil authUtil; @ApiOperation(value = "系统认证", notes = "系统认证")
@RequestMapping("/render")
public String renderAuth(String source) {
log.info("进入第三方认证:" + source);
Map<String, String> map = new HashMap<>();
AuthRequest authRequest = authUtil.getAuthRequest(source);
if (authRequest == null) {
map.put("code", "201");
map.put("msg", "系统未开启该登录方式");
return ServiceResult.success(map);
}
String token = AuthStateUtils.createState();
String authorizeUrl = authRequest.authorize(token);
log.info("获取返回url:" + authorizeUrl);
map.put("code", "200");
map.put("url", authorizeUrl);
return ServiceResult.success(map);
} }

拦截登录回调接口(ThirdPartyAuthenticationFilter)

import me.zhyd.oauth.model.AuthCallback;
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; /**
* 第三方登录-拦截器
* 拼接入参
*/
public class ThirdPartyAuthenticationFilter extends AbstractAuthenticationProcessingFilter { public static String EXTEND_LOGIN_URL = "/api/login/callback/**"; private boolean getOnly = true; /**
* 表示这个 Filter 拦截 /api/login/callback/** 接口
*/
private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher(EXTEND_LOGIN_URL, "GET"); public ThirdPartyAuthenticationFilter() {
super(DEFAULT_ANT_PATH_REQUEST_MATCHER);
} @Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (this.getOnly && !"GET".equals(request.getMethod())) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
} else {
ThirdPartyAuthenticationToken authRequest = new ThirdPartyAuthenticationToken(getSourceType(request), getCallback(request));
this.setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
} protected void setDetails(HttpServletRequest request, ThirdPartyAuthenticationToken authRequest) {
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
} /**
* 组装请求
*/
private AuthCallback getCallback(HttpServletRequest request) {
return AuthCallback.builder()
.code(request.getParameter("code"))
.auth_code(request.getParameter("auth_code"))
.authorization_code(request.getParameter("authorization_code"))
.oauth_token(request.getParameter("oauth_token"))
.state(request.getParameter("state"))
.oauth_verifier(request.getParameter("oauth_verifier"))
.build();
} /**
* 判断-登录系统类型
*/
private String getSourceType(HttpServletRequest request) {
String uri = request.getRequestURI();
int common = EXTEND_LOGIN_URL.length() - 2;
int start = uri.indexOf(EXTEND_LOGIN_URL.substring(0, common));
return uri.substring(start + common);
} }
封装用户信息(ThirdPartyAuthenticationToken)
import me.zhyd.oauth.model.AuthCallback;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority; import java.util.Collection; /**
* 模仿 UsernamePasswordAuthenticationToken
* 封装用户信息
*/
public class ThirdPartyAuthenticationToken extends AbstractAuthenticationToken { /**
* 认证返回
*/
private AuthCallback callback;
/**
* 登录类型
*/
private String source;
/**
* 用户实体
*/
private Object principal;
/**
* 用户id
*/
private Object credentials; public ThirdPartyAuthenticationToken(String source, AuthCallback callback) {
super(null);
this.source = source;
this.callback = callback;
setAuthenticated(false);
} public ThirdPartyAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
super.setAuthenticated(true);
} @Override
public Object getPrincipal() {
return principal;
} @Override
public Object getCredentials() {
return credentials;
} public Object getCallback() {
return callback;
} public Object getSource() {
return source;
}
}
第三方统一登录认证逻辑(ThirdPartyAuthenticationProvider)
package com.mxy.security.justauth;

import com.alibaba.fastjson.JSONObject;
import com.mxy.common.core.constant.Constants;
import com.mxy.common.core.entity.SelfUserEntity;
import com.mxy.common.core.entity.SysRole;
import com.mxy.common.core.entity.SysUser;
import com.mxy.common.core.entity.SysUserRole;
import com.mxy.common.core.utils.IPUtils;
import com.mxy.common.core.utils.RedisUtil;
import com.mxy.common.core.utils.ServletUtils;
import com.mxy.common.log.enums.OperType;
import com.mxy.security.security.service.SelfUserDetailsService;
import com.mxy.system.service.SysUserService;
import com.mxy.system.utils.LogUtil;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component; import javax.annotation.Resource;
import java.util.*; /**
* 第三方统一登录认证逻辑
*/
@Slf4j
@Component
public class ThirdPartyAuthenticationProvider implements AuthenticationProvider { @Autowired
private SelfUserDetailsService selfUserDetailsService;
@Autowired
private SysUserService sysUserService;
@Autowired
private RedisUtil redisUtil;
@Resource
private AuthUtil authUtil; @Resource
private BCryptPasswordEncoder bCryptPasswordEncoder; private Random random = new Random(); /**
* 第三方统一登录认证逻辑
*/
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
ThirdPartyAuthenticationToken token = (ThirdPartyAuthenticationToken) authentication;
String source = (String) token.getSource();
AuthCallback callback = (AuthCallback) token.getCallback();
log.info("------------进入" + source + "认证逻辑, callback params:" + JSONObject.toJSONString(callback));
AuthRequest authRequest = authUtil.getAuthRequest(source);
AuthResponse response = authRequest.login(callback);
if (response.getCode() == 5000) {
// 认证失败
throw new BadCredentialsException(source + "认证失败");
}
AuthUser authUser = (AuthUser) response.getData();
log.info("------------认证用户:{}", authUser);
// 根据 uuid 查询用户信息
SelfUserEntity userInfo = selfUserDetailsService.getUserInfoByUuid(authUser.getUuid());
if (userInfo == null) {
// 自动注册
userInfo = doRegister(authUser);
}
if (Constants.USER_STATE_TWO.equals(userInfo.getStatus())) {
LogUtil.saveLog("该账号已冻结[" + userInfo.getRelName() + "]", 99);
throw new LockedException("该账号已冻结");
}
// 角色集合
Set<GrantedAuthority> authorities = new HashSet<>();
// 查询用户角色
List<SysRole> sysRoleList = sysUserService.selectSysRoleByUserId(userInfo.getUserId());
for (SysRole sysRole : sysRoleList) {
authorities.add(new SimpleGrantedAuthority(sysRole.getRoleKey()));
}
userInfo.setAuthorities(authorities);
ThirdPartyAuthenticationToken authenticationResult = new ThirdPartyAuthenticationToken(userInfo, userInfo.getUserId(), userInfo.getAuthorities());
authenticationResult.setDetails(token.getDetails());
return authenticationResult;
} /**
* 账号注册
**/
public SelfUserEntity doRegister(AuthUser authUser) {
SelfUserEntity selfUser = new SelfUserEntity();
SysUser sysUser = new SysUser();
sysUser.setNickName(authUser.getNickname());
sysUser.setUsername(authUser.getSource() + (random.nextInt(89999999) + 10000000));
String password = String.valueOf(random.nextInt(899999) + 100000);
sysUser.setPassword(bCryptPasswordEncoder.encode(password));
sysUser.setAvatar(authUser.getAvatar());
sysUser.setRegistrationType(authUser.getSource());
sysUser.setUuid(authUser.getUuid());
sysUser.setLoginCount(0);
sysUser.setIpSource(IPUtils.getClientIp(Objects.requireNonNull(ServletUtils.getRequest())));
// 2-男
sysUser.setSex("2".equals(authUser.getRawUserInfo().getString("gender_type")) ? "0" : "1");
sysUser.setCreateUser("system");
sysUser.setRemark(authUser.getSource() + "首次注册默认密码为:" + password);
sysUser.setLoginDate(new Date());
sysUser.setUserType("2");
sysUser.insert(); // 新增用户角色关系
SysUserRole sysUserRole = new SysUserRole();
sysUserRole.setUserId(sysUser.getUserId());
// 游客
sysUserRole.setRoleId("2");
sysUserRole.insert();
BeanUtils.copyProperties(sysUser, selfUser);
selfUser.setRelName(sysUser.getNickName());
LogUtil.saveNoLoginLog("账号注册(" + authUser.getSource() + ")", JSONObject.toJSONString(sysUser), OperType.REGISTRATION.ordinal());
return selfUser;
} /**
* 判断是上面 authenticate 方法的 authentication 参数,是哪种类型
* Authentication 是个接口,实现类有很多,目前我们最熟悉的就是 ThirdPartyAuthenticationToken、UsernamePasswordAuthenticationToken
* 很明显,我们只支持 ThirdPartyAuthenticationToken,因为它封装的是TOKEN OPENID
*
* @param authentication
* @return
*/
@Override
public boolean supports(Class<?> authentication) {
return (ThirdPartyAuthenticationToken.class.isAssignableFrom(authentication));
}
}

工具类

import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.request.AuthGiteeRequest;
import me.zhyd.oauth.request.AuthQqRequest;
import me.zhyd.oauth.request.AuthRequest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; @Slf4j
@Component
public class AuthUtil { @Value("${justauth.qq.clientId}")
private String qqClientId; @Value("${justauth.qq.clientSecret}")
private String qqClientSecret; @Value("${justauth.qq.redirectUri}")
private String qqRedirectUri; @Value("${justauth.gitee.clientId}")
private String giteeClientId; @Value("${justauth.gitee.clientSecret}")
private String giteeClientSecret; @Value("${justauth.gitee.redirectUri}")
private String giteeRedirectUri; /**
* 鉴权
*/
public AuthRequest getAuthRequest(String source) {
AuthRequest authRequest = null;
switch (source) {
case "qq":
authRequest = new AuthQqRequest(AuthConfig.builder()
.clientId(qqClientId)
.clientSecret(qqClientSecret)
.redirectUri(qqRedirectUri)
.build());
break;
case "gitee":
authRequest = new AuthGiteeRequest(AuthConfig.builder()
.clientId(giteeClientId)
.clientSecret(giteeClientSecret)
.redirectUri(giteeRedirectUri)
.build());
break;
default:
break;
}
return authRequest;
} }
# 第三方登录秘钥
justauth:
qq:
clientId: xxxxxxxxxx
clientSecret: xxxxxxxxxxxx
redirectUri: http://xxxxxxxxxx/api/login/callback/qq
gitee:
clientId: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
clientSecret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
redirectUri: http://xxxxxxxxxx/api/login/callback/gitee

最新文章

  1. Struts2 DomainModel、ModelDriven接收参数
  2. XSS quiz练习题做题过程及感悟
  3. 精通正则表达式(第三版)——Mastering Regular Expressions,3rd Edition——读书笔记1
  4. VS2010 /VC/bin/rcdll.dll 无法找到资源编译器
  5. Design Mode 之 行为模式
  6. c/c++中使用指针需要注意的问题
  7. 一段代码说明javascript闭包执行机制
  8. jdbc详解(三)
  9. Oracle 性能优化 — 统计数据收集[Z]
  10. ExcelHelper Excel,Export,Import
  11. Java面试题-2
  12. Django字符串翻译
  13. 如何搭建python+selenium2+eclipse的环境
  14. CheckStyle检查规则中文翻译
  15. bootstrap修改勾选样式
  16. (转)Linux 文件目录特殊权限设定(SUID,SGID,SBIT)
  17. Golang context包解读
  18. Redis与高级语言内置的数据结构相比的异同及优势
  19. MongoDB - MongoDB CRUD Operations, Delete Documents
  20. java正则表达式(转)

热门文章

  1. DataX二次开发——新增HiveReader插件
  2. C# SMTP发邮件不支持465端口的解决方案
  3. .NET Core Redis的简单使用
  4. Vim-Adventures 有趣的Vim小游戏
  5. 【TS】函数重载--可选参数--默认参数
  6. Rpc-实现Client对ZooKeeper的服务监听
  7. 叠堆柱状图(带折线版+2y轴)
  8. 自动化测试如此容易!多语言自动化测试框架 Selenium 编程(C#篇)
  9. gitbook使用指南
  10. VSCode 国内镜像下载地址