三方登录
SpringBoot 实现App第三方微信登录 - uzxin - 博客园 (cnblogs.com)
(81条消息) OAuth三方授权登录_Java知音_的博客-CSDN博客
创建数据库表
-- ----------------------------
-- 第三方平台授权表
-- ----------------------------
create table sys_social
(
id int8 not null,
user_id int8 not null,
tenant_id varchar(20) default null::varchar,
auth_id varchar(255) not null,
source varchar(255) not null,
open_id varchar(255) default null::varchar,
user_name varchar(30) not null,
nick_name varchar(30) default ''::varchar,
email varchar(255) default ''::varchar,
avatar varchar(500) default ''::varchar,
access_token varchar(255) not null,
expire_in int8 default null,
refresh_token varchar(255) default null::varchar,
access_code varchar(255) default null::varchar,
union_id varchar(255) default null::varchar,
scope varchar(255) default null::varchar,
token_type varchar(255) default null::varchar,
id_token varchar(255) default null::varchar,
mac_algorithm varchar(255) default null::varchar,
mac_key varchar(255) default null::varchar,
code varchar(255) default null::varchar,
oauth_token varchar(255) default null::varchar,
oauth_token_secret varchar(255) default null::varchar,
create_dept int8,
create_by int8,
create_time timestamp,
update_by int8,
update_time timestamp,
del_flag char default '0'::bpchar,
constraint "pk_sys_social" primary key (id)
);
comment on table sys_social is '社会化关系表';
comment on column sys_social.id is '主键';
comment on column sys_social.user_id is '用户ID';
comment on column sys_social.tenant_id is '租户id';
comment on column sys_social.auth_id is '平台+平台唯一id';
comment on column sys_social.source is '用户来源';
comment on column sys_social.open_id is '平台编号唯一id';
comment on column sys_social.user_name is '登录账号';
comment on column sys_social.nick_name is '用户昵称';
comment on column sys_social.email is '用户邮箱';
comment on column sys_social.avatar is '头像地址';
comment on column sys_social.access_token is '用户的授权令牌';
comment on column sys_social.expire_in is '用户的授权令牌的有效期,部分平台可能没有';
comment on column sys_social.refresh_token is '刷新令牌,部分平台可能没有';
comment on column sys_social.access_code is '平台的授权信息,部分平台可能没有';
comment on column sys_social.union_id is '用户的 unionid';
comment on column sys_social.scope is '授予的权限,部分平台可能没有';
comment on column sys_social.token_type is '个别平台的授权信息,部分平台可能没有';
comment on column sys_social.id_token is 'id token,部分平台可能没有';
comment on column sys_social.mac_algorithm is '小米平台用户的附带属性,部分平台可能没有';
comment on column sys_social.mac_key is '小米平台用户的附带属性,部分平台可能没有';
comment on column sys_social.code is '用户的授权code,部分平台可能没有';
comment on column sys_social.oauth_token is 'Twitter平台用户的附带属性,部分平台可能没有';
comment on column sys_social.oauth_token_secret is 'Twitter平台用户的附带属性,部分平台可能没有';
comment on column sys_social.create_dept is '创建部门';
comment on column sys_social.create_by is '创建者';
comment on column sys_social.create_time is '创建时间';
comment on column sys_social.update_by is '更新者';
comment on column sys_social.update_time is '更新时间';
comment on column sys_social.del_flag is '删除标志(0代表存在 2代表删除)';
导入<justauth.version>1.16.5</justauth.version>
<!-- JustAuth 的依赖配置-->
<dependency>
<groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId>
<version>${justauth.version}</version>
</dependency>
配置yml
--- # 三方授权
justauth:
enabled: true
address: http://localhost:80
type:
qq:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=qq
union-id: false
weibo:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=weibo
gitee:
client-id: 914******************98
client-secret: 02*****************ac
redirect-uri: ${justauth.address}/social-callback?source=gitee
dingtalk:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=dingtalk
baidu:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=baidu
csdn:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=csdn
coding:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=coding
coding-group-name: xx
oschina:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=oschina
alipay:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=alipay
alipay-public-key: MIIB**************DAQAB
wechat_open:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_open
wechat_mp:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_mp
wechat_enterprise:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise
agent-id: 1000002
gitlab:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitlab
配置config
package com.xie.common.social.config.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* Social 配置属性
*
* @author thiszhc
*/
@Data
@Component
@ConfigurationProperties(prefix = "justauth")
public class SocialProperties {
/**
* 是否启用
*/
private Boolean enabled;
/**
* 授权类型java
*/
private Map<String, SocialLoginConfigProperties> type;
/**
* 授权过期时间
*/
private Long timeout;
}
package com.xie.common.social.config.properties;
import lombok.Data;
/**
* 社交登录配置
*
* @author thiszhc
*/
@Data
public class SocialLoginConfigProperties {
/**
* 应用 ID
*/
private String clientId;
/**
* 应用密钥
*/
private String clientSecret;
/**
* 回调地址
*/
private String redirectUri;
/**
* 是否获取unionId
*/
private boolean unionId;
/**
* Coding 企业名称
*/
private String codingGroupName;
/**
* 支付宝公钥
*/
private String alipayPublicKey;
/**
* 企业微信应用ID
*/
private String agentId;
/**
* stackoverflow api key
*/
private String stackOverflowKey;
/**
* 设备ID
*/java
private String deviceId;
/**
* 客户端系统类型
*/
private String clientOsType;
}
package com.xie.common.social.config;
import com.xie.common.social.config.properties.SocialProperties;
import com.xie.common.social.utils.AuthRedisStateCache;
import me.zhyd.oauth.cache.AuthStateCache;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
/**
* Social 配置属性
* @author thiszhca
*/
@AutoConfiguration
@EnableConfigurationProperties(SocialProperties.class)
public class SocialConfig {
@Bean
public AuthStateCache authStateCache(SocialProperties socialProperties) {
return new AuthRedisStateCache(socialProperties);
}
}
package com.xie.common.social.utils;
import com.xie.common.redis.utils.RedisUtils;
import com.xie.common.social.config.properties.SocialProperties;
import lombok.AllArgsConstructor;
import me.zhyd.oauth.cache.AuthStateCache;
import java.time.Duration;
/**
* 授权状态缓存
*/
@AllArgsConstructor
public class AuthRedisStateCache implements AuthStateCache {
private final SocialProperties socialProperties;
/**
* 存入缓存
*
* @param key 缓存key
* @param value 缓存内容
*/
@Override
public void cache(String key, String value) {
RedisUtils.setCacheObject(key, value, Duration.ofMillis(socialProperties.getTimeout()));
}
/**
* 存入缓存
*
* @param key 缓存key
* @param value 缓存内容
* @param timeout 指定缓存过期时间(毫秒)
*/
@Override
public void cache(String key, String value, long timeout) {
RedisUtils.setCacheObject(key, value, Duration.ofMillis(timeout));
}
/**
* 获取缓存内容
*
* @param key 缓存key
* @return 缓存内容
*/
@Override
public String get(String key) {
return RedisUtils.getCacheObject(key);
}
/**
* 是否存在key,如果对应key的value值已过期,也返回false
*
* @param key 缓存key
* @return true:存在key,并且value没过期;false:key不存在或者已过期
*/
@Override
public boolean containsKey(String key) {
return RedisUtils.hasKey(key);
}
}
登录流程
前端点击三方登录
// 绑定账号
export function authBinding(source: string) {
return request({
url: '/auth/binding/' + source,
method: 'get'
});
}
获取到地址传到前端
@GetMapping("/binding/{source}")
public R<String> authBinding(@PathVariable("source") String source) {
SocialLoginConfigProperties obj = socialProperties.getType().get(source);
if (ObjectUtil.isNull(obj)) {
return R.fail(source + "平台账号暂不支持");
}
AuthRequest authRequest = SocialUtils.getAuthRequest(source, socialProperties);
String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
return R.ok("操作成功", authorizeUrl);
}
authBinding(type).then((res: any) => {
if (res.code === 200) {
// 获取授权地址跳转
window.location.href = res.data;
} else {
ElMessage.error(res.msg);
}
在三方登录后进行回调
/**
* 第三方登录
*/
export function callback(data: LoginData): AxiosPromise<any> {
const LoginData = {
...data,
clientId: clientId,
grantType: 'social'
};
return request({
url: '/auth/social/callback',
method: 'post',
data: LoginData
});
}
@PostMapping("/social/callback")
public R<LoginVo> socialCallback(@RequestBody LoginBody loginBody) {
// 获取第三方登录信息
AuthResponse<AuthUser> response = SocialUtils.loginAuth(loginBody, socialProperties);
AuthUser authUserData = response.getData();
// 判断授权响应是否成功
if (!response.ok()) {
return R.fail(response.getMsg());
}
return loginService.sociaRegister(authUserData);
}
注册完成后插入sys_social表 就可以进行登录逻辑
登录逻辑
前端点击登录
// 绑定账号
export function authBinding(source: string) {
return request({
url: '/auth/binding/' + source,
method: 'get'
});
}
获取到source和code
进行登录
@Override
public LoginVo login(String clientId, LoginBody loginBody, SysClient client) {
AuthResponse<AuthUser> authUserAuthResponse = SocialUtils.loginAuth(loginBody, socialProperties);
if(!authUserAuthResponse.ok()){
throw new ServiceException(authUserAuthResponse.getMsg());
}
AuthUser data = authUserAuthResponse.getData();
String authId = data.getSource() + data.getUuid();
SysSocialVo sysSocialVo = sysSocialService.selectByAuthId(authId);
if(!ObjectUtil.isNotNull(sysSocialVo)){
throw new ServiceException("你还没有绑定第三方账号,绑定后才可以登录!");
}
// 查找用户
SysUserVo user = loadUser(sysSocialVo.getUserId());
LoginUser loginUser = sysLoginService.buildLoginUser(user);
SaLoginModel model = new SaLoginModel();
model.setDevice(client.getDeviceType());
// 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
// 例如: 后台用户30分钟过期 app用户1天过期
model.setTimeout(client.getTimeout());
model.setActiveTimeout(client.getActiveTimeout());
// 生成token
LoginHelper.login(loginUser, model);
LoginVo loginVo = new LoginVo();
loginVo.setAccessToken(StpUtil.getTokenValue());
return loginVo;
}
前端回调逻辑
if (!getToken()) {
await loginByCode(data);
} else {
await callbackByCode(data);
}