JustAuth 开箱即用的整合第三方登录的开源组件
如何使用
下面是对gitee第三方登录的整合
查看 授权登录流程
官网 JustAuth
在gitee创建第三方应用
- 获取生成的 Client ID
- 获取生成的 Client Secret
- 设置回调地址 http://127.0.0.1/oauth/callback?source=gitee
表设计
CREATE TABLE `social_user`
(
`id` bigint(20) NOT NULL COMMENT '主键',
`auth_id` varchar(255) NOT NULL COMMENT '第三方用户来源+第三方系统的唯一ID',
`source` varchar(255) NOT NULL COMMENT '第三方用户来源',
`uuid` varchar(255) NOT NULL COMMENT '第三方系统的唯一ID',
`user_name` varchar(30) NOT NULL COMMENT '登录账号',
`nick_name` varchar(30) DEFAULT '' COMMENT '用户昵称',
`email` varchar(255) DEFAULT '' COMMENT '用户邮箱',
`avatar` varchar(500) DEFAULT '' COMMENT '头像地址',
`access_token` varchar(255) NOT NULL COMMENT '用户的授权令牌',
`expire_in` int(11) DEFAULT NULL COMMENT '用户的授权令牌的有效期,部分平台可能没有',
`refresh_token` varchar(255) DEFAULT NULL COMMENT '刷新令牌,部分平台可能没有',
`open_id` varchar(255) DEFAULT NULL COMMENT '第三方用户的 open id,部分平台可能没有',
`access_code` varchar(255) DEFAULT NULL COMMENT '平台的授权信息,部分平台可能没有',
`union_id` varchar(255) DEFAULT NULL COMMENT '第三方用户的 union id,部分平台可能没有',
`scope` varchar(255) DEFAULT NULL COMMENT '第三方用户授予的权限,部分平台可能没有',
`token_type` varchar(255) DEFAULT NULL COMMENT '个别平台的授权信息,部分平台可能没有',
`id_token` varchar(255) DEFAULT NULL COMMENT 'id token,部分平台可能没有',
`mac_algorithm` varchar(255) DEFAULT NULL COMMENT '小米平台用户的附带属性,部分平台可能没有',
`mac_key` varchar(255) DEFAULT NULL COMMENT '小米平台用户的附带属性,部分平台可能没有',
`code` varchar(255) DEFAULT NULL COMMENT '用户的授权code,部分平台可能没有',
`oauth_token` varchar(255) DEFAULT NULL COMMENT 'Twitter平台用户的附带属性,部分平台可能没有',
`oauth_token_secret` varchar(255) DEFAULT NULL COMMENT 'Twitter平台用户的附带属性,部分平台可能没有',
`deleted` char(1) DEFAULT '0' COMMENT '删除标志',
PRIMARY KEY (`id`)
) ENGINE = InnoDB COMMENT ='社会化关系表';
CREATE TABLE `social_user_auth`
(
`id` bigint(20) NOT NULL COMMENT '主键',
`user_id` bigint(20) NOT NULL COMMENT '系统用户ID',
`user_type` tinyint(1) NOT NULL COMMENT '系统用户类型 1=管理后台用户、2=C端用户',
`social_user_id` bigint(20) NOT NULL COMMENT '社会化用户ID',
`deleted` char(1) DEFAULT '0' COMMENT '删除标志',
PRIMARY KEY (`id`)
) ENGINE = InnoDB COMMENT ='社会化用户 & 系统用户关系表';
添加依赖
我使用已经对justauth进行springboot封装后的 starter
<dependency>
<groupId>com.xkcoding.justauth</groupId>
<artifactId>justauth-spring-boot-starter</artifactId>
<version>1.4.0</version>
</dependency>
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--jedis作为连接池-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
配置文件
server:
port: 80
spring:
application:
name: jusauth-lab
main:
allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。
allow-bean-definition-overriding: true # 允许 Bean 覆盖,例如说 Dubbo 或者 Feign 等会存在重复定义的服务
mvc:
pathmatch:
matching-strategy: ANT_PATH_MATCHER # 解决 SpringFox 与 SpringBoot 2.6.x 不兼容的问题,参见 SpringFoxHandlerProviderBeanPostProcessor 类
redis:
host: 192.168.1.242
password: 123456
port: 6379
database: 0
timeout: 6000
jedis:
pool:
# 连接池最大连接数(使用负值表示没有限制)
max-active: 150
# 连接池中的最大空闲连接
max-idle: 20
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1
# 连接池中的最小空闲连接
min-idle: 8
justauth:
enabled: true
type:
GITEE:
client-id: 296dde6c2*********3dfbbb7688c8484afb4488eb21d12e
client-secret: cf59********366460d02f5f4b02b9ea83ce692dbd2392ed6c2fe7b61ca2b
redirect-uri: http://127.0.0.1/oauth/callback?source=gitee
cache:
type: redis
访问层
/**
* @author LGC
*/
@Slf4j
@RestController
@RequestMapping("/oauth")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class JustAuthController {
private final AuthRequestFactory factory;
/**
* 第三方应用名称列表
*
* @return
*/
@GetMapping("/list")
public List<String> list() {
return factory.oauthList();
}
/**
* 生成授权地址
* 前端来进行跳转,并设置回调地址
*
* @param source 来源
* @param redirectUri 前端重定向地址
* @throws IOException
*/
@GetMapping("/social-auth-redirect")
public String binding(@RequestParam("source") String source, @RequestParam("redirectUri") String redirectUri) throws IOException {
AuthRequest authRequest = factory.get(source);
// 生成跳转地址
String authorizeUri = authRequest.authorize(AuthStateUtils.createState());
// 替换重定向地址
UrlBuilder builder = UrlBuilder.of(authorizeUri, Charset.defaultCharset());
String key = "redirect_uri";
TableMap<CharSequence, CharSequence> query = (TableMap<CharSequence, CharSequence>)
ReflectUtil.getFieldValue(builder.getQuery(), "query");
query.remove(key);
// 后添加
builder.addQuery(key, redirectUri);
return builder.build();
}
/**
* 生成授权地址
* 后端进行跳转
*
* @param source 来源
* @param response
* @throws IOException
*/
@GetMapping("/redirect/{source}")
public void binding(@PathVariable String source, HttpServletResponse response) throws IOException {
AuthRequest authRequest = factory.get(source);
response.sendRedirect(authRequest.authorize(AuthStateUtils.createState()));
}
/**
* 由于没有前端,所以直接回调到后端
* 一般都是由前端解析回调参数然后传递给后端校验
*
* @param source 来源
* @param code code
* @param state state
* @return
*/
@RequestMapping("/callback")
public AuthResponse<AuthUser> callback(@RequestParam("source") String source,
@RequestParam("code") String code,
@RequestParam("state") String state) {
if (StrUtil.isBlank(code)) {
log.info("第三方用户拒绝授权,还可以更加其它参数进行判断,进行了缩减");
} else {
log.info("第三方用户同意授权,进行社交账号登录。。前端调用社交账号登录接口/socialLogin");
}
// 下面代码测试用
AuthRequest authRequest = factory.get(source);
AuthCallback callback = new AuthCallback();
callback.setCode(code);
callback.setState(state);
AuthResponse<AuthUser> authResponse = authRequest.login(callback);
log.info("authResponse:{}", JSONUtil.toJsonStr(authResponse));
AuthUser authUser = authResponse.getData();
AuthToken authToken = authUser.getToken();
log.info("authUser信息:{}", JSONUtil.toJsonStr(authUser));
log.info("authToken信息:{}", JSONUtil.toJsonStr(authToken));
return authResponse;
}
/**
* 社交账号登录
* 第三方用户同意授权时调用
*
* @param source 来源
* @param code code
* @param state state
* @return
*/
@RequestMapping("/socialLogin")
public Object socialLogin(@RequestParam("source") String source,
@RequestParam("code") String code,
@RequestParam("state") String state) {
log.info("获取第三方授权认证信息");
AuthRequest authRequest = factory.get(source);
AuthCallback callback = new AuthCallback();
callback.setCode(code);
callback.setState(state);
AuthResponse<AuthUser> authResponse = authRequest.login(callback);
log.info("保存或更新第三方授权认证信息");
log.info("判断是否绑定了系统账号,如果绑定了直接登录成功,没有绑定提示前端登录绑定");
return "登录信息";
}
/**
* 登录绑定
* 假设使用用户密码登录绑定第三方用户
*
* @param username 用户
* @param password 密码
* @param source 来源
* @return
*/
@RequestMapping("/login")
public Object login(@RequestParam("username") String username,
@RequestParam("password") String password,
@RequestParam("source") String source,
@RequestParam("code") String code,
@RequestParam("state") String state) {
log.info("账号密码登录");
log.info("获取第三方授权认证信息");
log.info("绑定系统用户,如果已绑定其它系统用户,解绑后在绑定");
return "登录信息";
}
}
测试
前端访问 http://127.0.0.1/oauth/redirect/gitee 地址回调到后端 /callback 接口