最近想把自己在公众号上介绍过的开源项目jeecg-boot项目跑起来,发现里面涉及到了集成第三方登录功能。光看项目的源码,自己也有点蒙圈,于是也去找了点资料学习了一天。今天把它分享在自己的公众号上,希望对想要在自己本地把jeecg-boot项目读者朋友们也会有所帮助。
说明
此 demo 主要演示 Spring Boot 项目如何使用 史上最全的第三方登录工具 - JustAuth 实现第三方登录,包括 QQ 登录、GitHub 登录、微信登录、谷歌登录、微软登录、小米登录、企业微信登录。
通过 justauth-spring-boot-starter 快速集成,好嗨哟~
JustAuth,如你所见,它仅仅是一个第三方授权登录的工具类库,它可以让我们脱离繁琐的第三方登录 SDK,让登录变得So easy!
全:已集成十多家第三方平台(国内外常用的基本都已包含),后续依然还有扩展计划!API 就是奔着最简单去设计的(见后面快速开始),尽量让您用起来没有障碍感!
非常感谢 @母狼 开源这个又好用又全面的第三方登录 SDK。
如果技术选型是 JFinal 的,请查看此demo: https://github.com/xkcoding/jfinal-justauth-demo
如果技术选型是 ActFramework 的,请查看此demo: https://github.com/xkcoding/act-justauth-demo
1.1. 公网服务器准备
首先准备一台有公网 IP 的服务器,可以选用阿里云或者腾讯云,如果选用的是腾讯云的,可以使用我的优惠链接购买。相比较而言,腾讯云的服务器的价格要便宜不少。
frp 安装程序下载地址:https://github.com/fatedier/frp/releases
目前最新稳定版本是0.35.1版本,而笔者尝试从这个网址下载发现windows系统的版本被禁止下载。所以笔者frp的服务端和客户端都只能安装在linux服务器上。
(1)使用root账户登录linux云服务器后将下载好的frp安装程序压缩包frp_0.35.1_linux_amd64.tar.gz上传到/usr/local目录下;
(2)执行cd /usr/local命令切换到压缩包所在目录后执行命令解压:tar -zxvf frp_0.35.1_linux_amd64.tar.gz;
(3)修改服务端配置文件:
执行 vim frps.ini
修改服务端配置文件
$ cd frp_0.35.1_linux_amd64
$ vim frps.ini
[common]
bind_port = 7100
vhost_http_port = 7200
默认bind_port=7000,这里把它改成了7100。然后执行esc+:
输入wq保存退出。
(4)启动 frps 服务
执行命令:./frps -c frps.ini
启动frps服务
[root@VM_0_10_centos frp_0.35.1_linux_amd64]# ./frps -c frps.ini
2021/03/14 11:24:40 [I] [root.go:108] frps uses config file: frps.ini
2021/03/14 11:24:40 [I] [service.go:190] frps tcp listen on 0.0.0.0:7100
2021/03/14 11:24:40 [I] [service.go:232] http service listen on 0.0.0.0:7200
2021/03/14 11:24:40 [I] [root.go:217] frps started successfully
(5)修改客户端配置文件
使用root账户另外起一个命令窗口,切换到/usr/local/frp_0.35.1_linux_amd64 目录执行命令vim ./frpc.ini修改frpc.ini
文件
# vim ./frpc.ini
[common]
server_addr = 127.0.0.1
server_port = 7100
[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 6000
[web]
type = http
local_port = 8080
custom_domains = javahsf.club
修改完成执行esc+:
输入wq保存退出。其他云服务器使用ssh远程连接frp服务需要走6000端口。以上端口都需要开通防火墙并在云服务器控制台添加安全组规则开通访问权限。
(6)启动frp客户端
执行命令./frpc -c frpc.ini
启动frp客户端
[root@VM_0_10_centos frp_0.35.1_linux_amd64]# ./frpc -c frpc.ini
2021/03/14 11:52:13 [I] [service.go:290] [6296aec6ddadbb5c] login to server success, get run id [6296aec6ddadbb5c], server udp port [0]
2021/03/14 11:52:13 [I] [proxy_manager.go:144] [6296aec6ddadbb5c] proxy added: [ssh web]
2021/03/14 11:52:13 [I] [control.go:180] [6296aec6ddadbb5c] [ssh] start proxy success
2021/03/14 11:52:13 [I] [control.go:180] [6296aec6ddadbb5c] [web] start proxy success
1.3 配置域名解
前往腾讯云控制台配置域名 DNS 解析,将域名解析到我们的公网服务器上,比如我的就是将 javahsf.club -> 134.175.187.61
配置域名解析之前,先要进行域名注册和备案,这个过程可能需要10天左右才能审批通过。
需要购买腾讯云服务器的朋友可以复制下面的连参与秒杀优惠活动,享有巨额优惠,首年仅95-99元!
【腾讯云】境外1核2G服务器低至2折,半价续费券限量免费领取!
1.4. nginx 代理
nginx 的搭建就不在此赘述了,只说配置
server {
listen 80;
server_name www.javahsf.club;
location / {
proxy_pass http://127.0.0.1:7200;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_buffering off;
sendfile off;
proxy_max_temp_file_size 0;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_temp_file_write_size 64k;
proxy_http_version 1.1;
proxy_request_buffering off;
}
}
测试配置文件是否有问题
# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
重新加载配置文件,使其生效
#nginx -s reload
现在当我们在浏览器输入 javahsf.club 的时候,网络流量其实会经历以下几个步骤:
(1)通过之前配的 DNS 域名解析会访问到我们的公网服务器 134.175.187.61 的 80 端口
(2)再经过 nginx,代理到本地的 7200 端口
(3)再经过 frp 穿透到本地的 8080 端口
(4)此时 8080 就是我们的应用程序端口
查看完整代码
我们可以把完整的demo代码克隆下来或者下载源码压缩包后在本地磁盘解压后使用IDEA打开源码
2.1 pom.xm
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<artifactId>spring-boot-demo-socialartifactId>
<version>1.0.0-SNAPSHOTversion>
<packaging>jarpackaging>
<name>spring-boot-demo-socialname>
<description>Demo project for Spring Bootdescription>
<parent>
<groupId>com.xkcodinggroupId>
<artifactId>spring-boot-demoartifactId>
<version>1.0.0-SNAPSHOTversion>
parent>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<java.version>1.8java.version>
<justauth-spring-boot.version>1.0.0justauth-spring-boot.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-pool2artifactId>
dependency>
<dependency>
<groupId>com.xkcodinggroupId>
<artifactId>justauth-spring-boot-starterartifactId>
<version>${justauth-spring-boot.version}version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>com.google.guavagroupId>
<artifactId>guavaartifactId>
dependency>
<dependency>
<groupId>cn.hutoolgroupId>
<artifactId>hutool-allartifactId>
dependency>
dependencies>
<build>
<finalName>spring-boot-demo-socialfinalName>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
源码使用的是2.1.0-RELEASE
版本的SpringBoot
2.2 application.yml
server:
port:8080
servlet:
context-path:/demo
spring:
redis:
host:localhost
# 连接超时时间(记得添加单位,Duration)
timeout:10000ms
# Redis默认情况下有16个分片,这里配置具体使用的分片
# database: 0
lettuce:
pool:
# 连接池最大连接数(使用负值表示没有限制) 默认 8
max-active:8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
max-wait:-1ms
# 连接池中的最大空闲连接 默认 8
max-idle:8
# 连接池中的最小空闲连接 默认 0
min-idle:0
cache:
# 一般来说是不用配置的,Spring Cache 会根据依赖的包自行装配
type:redis
justauth:
enabled:true
type:
qq:
client-id:10******85
client-secret:1f7d************************d629e
redirect-uri:http://javahsf.club/demo/oauth/qq/callback
github:
client-id:7464*****************************da36094474e
client-secret:5a2919b************************d7871306d1
redirect-uri:http://javahsf.club/demo/oauth/github/callback
wechat:
client-id:wxdcb******4ff4
client-secret:b4e9dc************************a08ed6d
redirect-uri:http://javahsf.club/demo/oauth/wechat/callback
google:
client-id:716******17-6db******vh******ttj320i******userco******t.com
client-secret:9IBorn************7-E
redirect-uri:http://javahsf.club/demo/oauth/google/callback
microsoft:
client-id:7bdce8******************e194ad76c1b
client-secret:Iu0zZ4************************tl9PWan_.
redirect-uri:https://javahsf.club/demo/oauth/microsoft/callback
mi:
client-id:288************2994
client-secret:nFeTt89************************==
redirect-uri:http://javahsf.club/demo/oauth/mi/callback
wechat_enterprise:
client-id:ww58******f3************fbc
client-secret:8G6PCr00j************************rgk************AyzaPc78
redirect-uri:http://javahsf.club/demo/oauth/wechat_enterprise/callback
agent-id:1******2
以上需要将源码中的域名oauth.xkcoding.com
改为自己注册的域名javahsf.club
2.3 OauthController.java
@Slf4j
@RestController
@RequestMapping("/oauth")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
publicclass TestController {
privatefinal AuthRequestFactory factory;
@GetMapping
public List<String> list() {
return factory.oauthList();
}
/**
*第三方登录接口
*/
@GetMapping("/login/{type}")
public void login(@PathVariable String type, HttpServletResponse response) throws IOException {
AuthRequest authRequest = factory.get(type);
response.sendRedirect(authRequest.authorize(AuthStateUtils.createState()));
}
/**
*第三方认证登录成功后的回调接口
*/
@RequestMapping("/{type}/callback")
public AuthResponse login(@PathVariable String type, AuthCallback callback) {
AuthRequest authRequest = factory.get(type);
AuthResponse response = authRequest.login(callback);
log.info("【response】= {}", JSONUtil.toJsonStr(response));
return response;
}
}
2.4 默认缓存实现
(1)配置缓存
starter 内置了2种缓存实现,一种是上面的默认实现,另一种是基于 Redis 的缓存实现。
当然了,你也可以自定义实现你自己的缓存在配置文件配置如下内容即可:
justauth:
cache:
type:default
(2) Redis 缓存实现
添加 Redis 相关依赖:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-pool2artifactId>
dependency>
配置文件配置如下内容即可:
justauth:
cache:
type:redis
# 缓存前缀,目前只对redis缓存生效,默认 JUSTAUTH::STATE::
prefix:''
# 超时时长,目前只对redis缓存生效,默认3分钟
timeout:1h
spring:
redis:
host:localhost
# 连接超时时间(记得添加单位,Duration)
timeout:10000ms
# Redis默认情况下有16个分片,这里配置具体使用的分片
# database: 0
lettuce:
pool:
# 连接池最大连接数(使用负值表示没有限制) 默认 8
max-active:8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
max-wait:-1ms
# 连接池中的最大空闲连接 默认 8
max-idle:8
# 连接池中的最小空闲连接 默认 0
min-idle:0
2.4 自定义缓存实现
(1)在application.yml
配置文件中配置中修改justauth.cache.type
justauth:
cache:
type:custom
(2)自定义缓存实现AuthStateCache
接口
/**
*
* 自定义缓存实现
*
* @author yangkai.shen
* @date Created in 2019/8/31 12:53
*/
publicclass MyAuthStateCache implements AuthStateCache {
/**
* 存入缓存
*
* @param key 缓存key
* @param value 缓存内容
*/
@Override
public void cache(String key, String value) {
// TODO: 自定义存入缓存
}
/**
* 存入缓存
*
* @param key 缓存key
* @param value 缓存内容
* @param timeout 指定缓存过期时间(毫秒)
*/
@Override
public void cache(String key, String value, long timeout) {
// TODO: 自定义存入缓存
}
/**
* 获取缓存内容
*
* @param key 缓存key
* @return 缓存内容
*/
@Override
public String get(String key) {
// TODO: 自定义获取缓存内容
returnnull;
}
/**
* 是否存在key,如果对应key的value值已过期,也返回false
*
* @param key 缓存key
* @return true:存在key,并且value没过期;false:key不存在或者已过期
*/
@Override
public boolean containsKey(String key) {
// TODO: 自定义判断key是否存在
returnfalse;
}
}
(3)自动装配
JustAuthConfig
/**
*
* 自定义缓存装配
*
*
* @author yangkai.shen
* @date Created in 2019/8/31 12:29
*/
@Configuration
publicclass AuthStateConfiguration {
@Bean
public AuthStateCache authStateCache() {
returnnew MyAuthStateCache();
}
}
3.1 QQ 互联平台申请
(1)前往 https://connect.qq.com/
(2)注册成为开发者
(3)应用管理 -> 添加移动应用或网站应用,等待审核通过即可
操作详细可参考:QQ互联官方指导文档
由于笔者在自己的电脑上进入相关页面进行注册成为QQ互联开发者操作一直失败,为了节省时间这里就不演示了。
3.2 微信开放平台申请
这里微信开放平台需要用企业的,个人没有资质,个人需要开通可以走以下两种方式:
(1)店铺支持帮你过企业资质,这里就用你自己的开放平台号就好了
(2)临时使用可以问店家租一个月进行开发,这里租了之后,店家会把 AppID 和 AppSecret 的信息发给你,你提供回调域就好了
因为笔者没有开通企业微信认证资质,也没有去某宝租赁,所以就不方便进一步演示了。
需要申请企业微信认证的读者可以参考这篇文章:使用 JustAuth 集成企业微信
3.3 gitee 平台认证开通
(1)进入码云中国官网 https://gitee.com登录个人账户后 鼠标悬停头像处在弹出的下拉菜单中时点击“设置”进入用户信息页面https://gitee.com/profile/account_information
(2)点击左下方的“第三方应用”进入https://gitee.com/oauth/applications页面点击右上角“创建应用”按钮创建你的应用
(3)在便捷界面输入应用名称、应用描述、应用主页和应用回调地址并上传应用logo图片后点击左下方的创建应用
(4)创建应用成功后点击“我的应用”进入刚才创建的应用,可以看到client id
和client secret
,将其复制到项目的application.yml
文件的gitee的client-id
和client-secret
变量对应的值位置
justauth:
type:
gitee:
client-id:7464****90a4fe3da36094474ea
client-secret:426d********5ca7af03ad0c
3.3 github平台开通认证
(1)前往 https://github.com/settings/developers
(2)点击 New OAuth App 按钮创建应用
(3)上传好Applicatioin logo图片,并填写完Badge background color、 Application name、Application description、Homepage URL、Authorization callback URL等各项内容后点击下方的"Register application"完成应用的创建
(4)创建应用完成后进入应用,把client id和client复制过来拷贝到项目的application.yml文件的github的client-id和client-secret变量对应的值位置
justauth:
enabled:true
type:
github:
client-id:d2ee******734e
client-secret:d415**********6d98d6b
4.1 项目打成jar包
在demo-socail
项目所在的根目录下选中盘符上的目录,输入cmd回车进入dos命令控制台执行mvn clean package
把项目打成jar包(需要在本地安装Maven),然后进入target目录可以看到一个social-demo.jar
文件
4.2 jar包部署到服务器
(1)使用root账户登录云服务器,执行cd /usr/local
命令切换到/usr/local目录,执行mkdir springboot_socail
新建springboot_socail目录
(2)使用ftp 将本地的 social-demo.jar
文件上传到/usr/local/springboot_socail
目录;
(3)cd ./springboot_socail
切换到jar包所在目录新建应用启动脚本文件startup.sh
和关闭应用脚本文件stop.sh
startup.sh
脚本文件内容如下:
#!/bin/bash
jar_name=demo-social.jar
port=8080
log_path=./log_social
ID=`ps -ef | grep $port | grep -v "grep" | awk '{print $2}'`
echo$ID
if [ {$ID} ]; then
echo'App is Running,Kill the Proccess!'
kill -9 $ID
echo'Stop Success!'
fi
rm -rf $log_path
mkdir $log_path
echo'Start to Running the Application!'
nohup java -jar -Dlogging.path=$log_path$jar_name>$log_path/catalina.out 2>&1 &
tail -f $log_path/catalina.out
stop.sh
脚本文件内容如下:
#!/bin/bash
port=8080
ID=`ps -ef | grep $port | grep -v "grep" | awk '{print $2"}'`
if [ ${ID} ]; then
echo'the application process id is $ID'
echo'kill the prcocess!'
kill -9 $ID
echo'stopped the application success!'
else
echo'the application is already stopped!'
fi
保存后分别执行 chmod 775 ./startup.sh和chmod 775 ./stop.sh给root及其同组用户赋予读、写和执行权限。
(4)执行 ./startup.sh
启动应用,当控制台出现以下日志时说明应用启动成功
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.0.RELEASE)
2021-03-15 23:12:03.038 INFO 727 --- [ main] c.x.s.SpringBootDemoSocialApplication : Starting SpringBootDemoSocialApplication on VM_0_10_centos with PID 727 (/usr/local/springboot_socail/demo-social.jar started by root in /usr/local/springboot_socail)
2021-03-15 23:12:03.051 INFO 727 --- [ main] c.x.s.SpringBootDemoSocialApplication : No active profile set, falling back to default profiles: default
2021-03-15 23:12:05.235 INFO 727 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
2021-03-15 23:12:05.238 INFO 727 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode.
2021-03-15 23:12:05.310 INFO 727 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 39ms. Found 0 repository interfaces.
2021-03-15 23:12:06.883 INFO 727 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2021-03-15 23:12:06.930 INFO 727 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2021-03-15 23:12:06.931 INFO 727 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/9.0.12
5.1 gitee平台登录认证
(1)打开谷歌浏览器,输入http://javahsf.club/demo/oauth/login/gitee
回车后发现页面跳转到了gitee平台的授权认证页面
(2)点确认后浏览器通过回调URL把用户在gitee平台注册的认证信息及认证token等信息携带了回来。
浏览器URL变为了如下带code和state参数的认证成功后的回调地址:
http://javahsf.club/demo/oauth/gitee/callback?code=b242c38172b78386a20bb1daf1a34d1cea81cdd9e38d0ee65a88016f7c6028a1&state=gitee%3A%3Ac396dde44b789c6e2d83112dd01866a1
同时浏览器中返回了用户的认证信息:
{"code":2000,
"msg":null,
"data":
{ "uuid":"2060016",
"username":"heshengfu1211",
"nickname":"heshengfu26",
"avatar":"https://gitee.com/assets/no_portrait.png",
"blog":"https://blog.csdn.net/heshengfu1211",
"source":"GITEE",
"token":
{"accessToken":"60a82dba008cb87f8597335acac85c3d",
"expireIn":86400,
"refreshToken":"e0e07899066774a0a1a01d32bb85c19719710b99665cd572a81392f736572214",
"uid":null,
"openId":null,
"accessCode":null,
"unionId":null,
"scope":"user_info",
"tokenType":"bearer",
"idToken":null,
"macAlgorithm":null,
"macKey":null,
"code":null
}
}
}
5.2 github 平台登录认证
(1)打开谷歌浏览器,输入http://javahsf.club/demo/oauth/login/github
回车后发现页面跳转到了gitee平台的授权认证页面
(2)点确认后浏览器通过回调URL把用户在github平台注册的认证信息及认证token等信息携带了回来。
浏览器URL变为了如下带code和state参数的认证成功后的回调地址:
http://javahsf.club/demo/oauth/github/callback?code=fc24db06bcf9f96bb3d1&state=github%3A%3A43881b142bfba6e01844d39414c40a91
同时浏览器中返回了用户的认证信息:
{"code":2000,
"msg":null,
"data":
{"uuid":null,
"username":null,
"nickname":null,
"avatar":null,
"blog":null,
"company":null,
"location":null,
"email":null,
"remark":null,
"gender":"UNKNOWN",
"source":"GITHUB",
"token":
{"accessToken":"9aee2af2406a10c9414818fe1b0ed2e8f596af69",
"expireIn":0,
"refreshToken":null,
"uid":null,
"openId":null,
"accessCode":null,
"unionId":null,
"scope":null,
"tokenType":"bearer",
"idToken":null,
"macAlgorithm":null,
"macKey":null,
"code":null
}
}
}
由此可见,第三方平台认证本质上是给用户授权了一个可以访问应用的accessToken。
[1] Spring Boot 快速集成第三方登录功能
[2] justauth-spring-boot-starter项目源码
[3] Nginx部署多个spring-boot项目(jar方式部署)
声明:原创不易,本文首发个人公众号“阿福谈Java技术栈”,转载请注明出处。觉得作者的文章对你有帮助的话欢迎使用微信扫码下方二维码添加作者个人的微信公众号