Compare commits
77 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 10df9f05f3 | |||
| fd183afd4a | |||
| d48a62d5cb | |||
| b466dd8de3 | |||
| 4d8411e978 | |||
| cf77e4d0e0 | |||
| 4f303705d9 | |||
| 1fb8be6c82 | |||
| 48a368b516 | |||
| 6594d90a71 | |||
| 31c983234f | |||
| 52682debfb | |||
| d5e161eaef | |||
| 1ab1cc124a | |||
| 050686d85f | |||
| 05f95b86b4 | |||
| 665daa37b2 | |||
| 576402eec3 | |||
| ec6c7a92b6 | |||
| d44cbd6e2b | |||
| 15caef01d3 | |||
| ad2e7c8231 | |||
| 57a7b7ff17 | |||
| 7a40159d15 | |||
| bcb27e4118 | |||
| 0b9cb95103 | |||
| d61bb58b93 | |||
| d034722232 | |||
| 197f15dc4f | |||
| fcb6fd9937 | |||
| ce5c437289 | |||
| fabfff60c9 | |||
| d4296d160e | |||
| d9967b2814 | |||
| 267b74bed7 | |||
| 3e8c475d3f | |||
| c1f9e96a92 | |||
| bed01eef6d | |||
| 909702e4da | |||
| 57cb7fb0d1 | |||
| b9c29c7534 | |||
| 6474c46505 | |||
| 864665f1b8 | |||
| 83d23302f8 | |||
| ca1522adfd | |||
| 55459652b9 | |||
| 92bc4ab34a | |||
| 4fab7561a4 | |||
| 16918ea13f | |||
| eec26580c9 | |||
| 421cabb176 | |||
| f71fce6858 | |||
| 3199334ddc | |||
| 79417395a1 | |||
| 06934b5242 | |||
| fcaef297ff | |||
| e590077701 | |||
| 6ce26d4ce1 | |||
| 43d9ec8631 | |||
| 8e99e54519 | |||
| 33076971fe | |||
| a2d6dfe707 | |||
| 64aa1940e4 | |||
| 56c1e4ea35 | |||
| ea1e1ba665 | |||
| 55c4b391bc | |||
| 094c297920 | |||
| 7f725b579b | |||
| 66a68c4ead | |||
| 504bf1cc7c | |||
| 97e7018795 | |||
| 993dc687fc | |||
| 38264616b4 | |||
| a75bac2cf7 | |||
| 666d50b461 | |||
| 7515301f50 | |||
| cab222059c |
@@ -1,13 +1,12 @@
|
||||
### 哪个平台?
|
||||
为更快的帮您定位问题,推荐您用以下模板反馈问题:
|
||||
|
||||
### 1. 出现问题时,您做了哪些操作?
|
||||
|
||||
### 2. 在哪个步骤出现了问题?
|
||||
|
||||
### 重现步骤
|
||||
|
||||
|
||||
|
||||
### 报错信息
|
||||
|
||||
### 3. 您希望得到什么结果?
|
||||
|
||||
### 4. 您实际得到什么结果?
|
||||
|
||||
### 5. 请附上您出现问题的整屏截图或者整个异常堆栈信息
|
||||
|
||||
|
||||
@@ -1,15 +1,26 @@
|
||||
### 该Pull Request关联的Issue
|
||||
[ ] 是否为解决Issue?
|
||||
|
||||
|
||||
### 修改描述
|
||||
|
||||
|
||||
|
||||
### 测试用例
|
||||
|
||||
|
||||
|
||||
### 修复效果的截屏
|
||||
### 您做了哪些更新?
|
||||
|
||||
#### 新增
|
||||
|
||||
#### 修改
|
||||
|
||||
#### 修复
|
||||
|
||||
#### 其他
|
||||
|
||||
|
||||
### 是否做了充分测试?
|
||||
|
||||
- [ ] 是,已经做过测试,并且测试通过
|
||||
- [ ] 否,还没做测试,需要作者自测
|
||||
|
||||
注:测试demo可以使用:
|
||||
- [Springboot版](https://gitee.com/yadong.zhang/JustAuth-demo)
|
||||
- [jFinal版](https://github.com/xkcoding/jfinal-justauth-demo)
|
||||
- [ActFramework版](https://github.com/xkcoding/act-justauth-demo)
|
||||
|
||||
|
||||
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
language: java
|
||||
|
||||
sudo: false # faster builds
|
||||
|
||||
install: true
|
||||
|
||||
jdk:
|
||||
- openjdk8
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
script:
|
||||
- export TZ=Asia/Shanghai
|
||||
- mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V
|
||||
- mvn cobertura:cobertura -Dcobertura.report.format=xml -Dmaven.javadoc.skip.true
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
@@ -6,7 +6,7 @@
|
||||
</p>
|
||||
<p align="center">
|
||||
<a target="_blank" href="https://search.maven.org/search?q=JustAuth">
|
||||
<img src="https://img.shields.io/badge/Maven Central-1.9.1-blue.svg" ></img>
|
||||
<img src="https://img.shields.io/badge/Maven Central-1.10.1-blue.svg" ></img>
|
||||
</a>
|
||||
<a target="_blank" href="https://gitee.com/yadong.zhang/JustAuth/blob/master/LICENSE">
|
||||
<img src="https://img.shields.io/apm/l/vim-mode.svg?color=yellow" ></img>
|
||||
@@ -14,8 +14,20 @@
|
||||
<a target="_blank" href="https://www.oracle.com/technetwork/java/javase/downloads/index.html">
|
||||
<img src="https://img.shields.io/badge/JDK-1.8+-green.svg" ></img>
|
||||
</a>
|
||||
<a target="_blank" href="https://apidoc.gitee.com/yadong.zhang/JustAuth/">
|
||||
<img src="https://img.shields.io/badge/Docs-1.9.1-orange.svg" ></img>
|
||||
<a target="_blank" href="https://apidoc.gitee.com/yadong.zhang/JustAuth/" title="API文档">
|
||||
<img src="https://img.shields.io/badge/Api Docs-1.10.1-orange.svg" ></img>
|
||||
</a>
|
||||
<a target="_blank" href="https://docs.justauth.whnb.wang" title="参考文档">
|
||||
<img src="https://img.shields.io/badge/Docs-latest-blueviolet.svg" ></img>
|
||||
</a>
|
||||
<a href="https://codecov.io/gh/zhangyd-c/JustAuth">
|
||||
<img src="https://codecov.io/gh/zhangyd-c/JustAuth/branch/master/graph/badge.svg" />
|
||||
</a>
|
||||
<a href='https://gitee.com/yadong.zhang/JustAuth/stargazers'>
|
||||
<img src='https://gitee.com/yadong.zhang/JustAuth/badge/star.svg?theme=white' alt='star'></img>
|
||||
</a>
|
||||
<a target="_blank" href='https://github.com/zhangyd-c/JustAuth'>
|
||||
<img src="https://img.shields.io/github/stars/zhangyd-c/JustAuth.svg?style=social" alt="github star"></img>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -49,6 +61,8 @@
|
||||
<td align="center" width="200"><a href="#授权人人"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/renren.png" width="20"></a></td>
|
||||
<td align="center" width="200"><a href="#授权Pinterest"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/pinterest.png" width="20"></a></td>
|
||||
<td align="center" width="200"><a href="#授权Stack Overflow"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/stackoverflow.png" width="20"></a></td>
|
||||
<td align="center" width="200"><a href="#授权华为"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/huawei.png" width="20"></a></td>
|
||||
<td align="center" width="200"><a href="#授权微信企业版" title="微信企业版"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/wechat.png" width="20"></a></td>
|
||||
<td align="center" width="200"><a href="#授权csdn"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/csdn.png" width="20"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -60,7 +74,8 @@
|
||||
|
||||
JustAuth,如你所见,它仅仅是一个**第三方授权登录**的**工具类库**,它可以让我们脱离繁琐的第三方登录SDK,让登录变得**So easy!**
|
||||
|
||||
项目开源地址:[gitee](https://gitee.com/yadong.zhang/JustAuth) | [github](https://github.com/zhangyd-c/JustAuth)
|
||||
项目开源地址:[gitee](https://gitee.com/yadong.zhang/JustAuth) | [github](https://github.com/zhangyd-c/JustAuth)
|
||||
项目文档:[参考文档](https://docs.justauth.whnb.wang)
|
||||
|
||||
## 特点
|
||||
|
||||
@@ -76,7 +91,7 @@ JustAuth,如你所见,它仅仅是一个**第三方授权登录**的**工具
|
||||
<dependency>
|
||||
<groupId>me.zhyd.oauth</groupId>
|
||||
<artifactId>JustAuth</artifactId>
|
||||
<version>1.9.1</version>
|
||||
<version>1.10.1</version>
|
||||
</dependency>
|
||||
```
|
||||
- 调用api
|
||||
@@ -86,19 +101,26 @@ AuthRequest authRequest = new AuthGiteeRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.state("state")
|
||||
.build());
|
||||
// 生成授权页面
|
||||
authRequest.authorize();
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的参数
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
authRequest.login(callback);
|
||||
```
|
||||
|
||||
注:`1.8.0`版本后,增加了`state`参数校验,用于防止[CSRF](https://zh.wikipedia.org/wiki/%E8%B7%A8%E7%AB%99%E8%AF%B7%E6%B1%82%E4%BC%AA%E9%80%A0)。强烈建议,保证单次流程内`state`的唯一性,且每个`state`只可用一次。
|
||||
|
||||
**配套Demo**:
|
||||
- [Springboot版](https://gitee.com/yadong.zhang/JustAuth-demo)
|
||||
- [jFinal版](https://github.com/zhangyd-c/jfinal-justauth-demo)
|
||||
- [jFinal版](https://github.com/xkcoding/jfinal-justauth-demo)
|
||||
- [ActFramework版](https://github.com/xkcoding/act-justauth-demo)
|
||||
|
||||
**扩展工具**
|
||||
|
||||
- [justauth-spring-boot-starter](https://github.com/xkcoding/justauth-spring-boot-starter): Spring Boot 集成 JustAuth 的最佳实践
|
||||
|
||||
**配套SpringBoot starter**:
|
||||
|
||||
[justauth-spring-boot-starter](https://github.com/xkcoding/justauth-spring-boot-starter)
|
||||
|
||||
具体的例子可以参考:
|
||||
|
||||
@@ -132,6 +154,8 @@ authRequest.login(callback);
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/renren.png" width="20"> | [AuthRenrenRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthRenrenRequest.java) | <a href="http://open.renren.com/wiki/OAuth2.0" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/pinterest.png" width="20"> | [AuthPinterestRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthPinterestRequest.java) | <a href="https://developers.pinterest.com/docs/api/overview/?" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/stackoverflow.png" width="20"> | [AuthStackOverflowRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthStackOverflowRequest.java) | <a href="https://api.stackexchange.com/docs/authentication" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/huawei.png" width="20"> | [AuthHuaweiRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthHuaweiRequest.java) | <a href="https://developer.huawei.com/consumer/cn/devservice/doc/30101" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/wechat.png" width="20"> | [AuthWeChatEnterpriseRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthWeChatEnterpriseRequest.java) | <a href="https://open.work.weixin.qq.com/api/doc#90000/90135/90664" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/csdn.png" width="20"> | [AuthCsdnRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthCsdnRequest.java) | 无 |
|
||||
|
||||
_请知悉:经咨询CSDN官方客服得知,CSDN的授权开放平台已经下线。如果以前申请过的应用,可以继续使用,但是不再支持申请新的应用。so, 本项目中的CSDN登录只能针对少部分用户使用了_
|
||||
@@ -159,6 +183,8 @@ _请知悉:经咨询CSDN官方客服得知,CSDN的授权开放平台已经
|
||||
|
||||
[阿里妈妈MUX倾力打造的矢量图标库-iconfont](https://www.iconfont.cn/search/index): 本文档中的图标大部分取自该平台
|
||||
|
||||
[mica](https://github.com/lets-mica/mica):Spring Cloud 微服务开发核心包,支持 `web `和 `webflux`。注:JustAuth项目中的[UuidUtils](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/utils/UuidUtils.java)就是直接使用的mica提供的高性能的uuid创建工具类源码[StringUtil.java](https://github.com/lets-mica/mica/blob/master/mica-core/src/main/java/net/dreamlu/mica/core/utils/StringUtil.java#L335)
|
||||
|
||||
## 关于OAuth
|
||||
|
||||
[The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749)
|
||||
@@ -173,7 +199,7 @@ _请知悉:经咨询CSDN官方客服得知,CSDN的授权开放平台已经
|
||||
|
||||
- JustAuth交流群 (230017570):专业交流该项目
|
||||
|
||||
- 开源总群 (190886500):各个开源项目的都有,也有博客建设等方面的朋友。(注意,该群需付费进入,防止发垃圾广告、垃圾推广等人士)
|
||||
- 开源总群 (190886500):各个开源项目的都有,也有博客建设等方面的朋友。
|
||||
|
||||
|
||||
## 请喝咖啡
|
||||
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
## ~~升级到1.8.0后如何启用state?~~
|
||||
|
||||
~~在原api使用方法的基础上,为config追加一个state即可。~~
|
||||
```
|
||||
AuthRequest authRequest = new AuthGiteeRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.state("state") // 就是这儿
|
||||
.build());
|
||||
```
|
||||
|
||||
## ~~升级到1.8.0后login方法报错?~~
|
||||
|
||||
~~这是因为1.8.0版本中新增了[AuthCallback](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/model/AuthCallback.java)类,这个类封装了所有可能的回调参数。目前包含以下三个参数:~~
|
||||
- ~~`code`: 访问AuthorizeUrl后回调时带的参数code,用来换取token~~
|
||||
- ~~`auth_code`: 支付宝授权登陆时不会返回code而是返回`auth_code`参数~~
|
||||
- ~~`state`: 访问AuthorizeUrl后回调时带的参数state,用于和请求AuthorizeUrl前的state比较,防止CSRF攻击~~
|
||||
|
||||
~~1.8.0版本之后的api,可以直接用AuthCallback类作为回调方法的入参,比如:~~
|
||||
```
|
||||
@RequestMapping("/callback/{source}")
|
||||
public Object login(@PathVariable("source") String source, AuthCallback callback) {
|
||||
System.out.println("进入callback:" + source + " callback params:" + JSONObject.toJSONString(callback));
|
||||
AuthRequest authRequest = getAuthRequest(source);
|
||||
AuthResponse response = authRequest.login(callback);
|
||||
System.out.println(JSONObject.toJSONString(response));
|
||||
return response;
|
||||
}
|
||||
```
|
||||
~~_代码截取自_ :https://gitee.com/yadong.zhang/JustAuth-demo~~
|
||||
|
||||
## ~~升级到1.8.0后对于state参数有什么特殊要求吗?~~
|
||||
|
||||
~~理论上没有,stata只是用来保持会话状态,因为http协议的无状态性,从授权到回调,无法感知具体是哪个用户触发的。所以可以使用state作为校验。注:state参数每次完整的授权链中只可用一次!(也是为了防止不必要的危险)~~
|
||||
|
||||
~~作者建议state命名格式如下:~~
|
||||
- ~~授权登录:`{source}_{ip}_{random}`~~
|
||||
- ~~账号绑定:`{source}_{userId}_{ip}_{random}`~~
|
||||
|
||||
~~其中`source`表示授权平台,可以直接去JustAuth中的source,`ip`为当前用户的ip(部分情况可能不适用),`random`为随机字符串,`userId`为当前登录用户的id。~~
|
||||
|
||||
~~注:`authorize`和`login`(不是指回调传回的`state`,而是声明`request`时传入的`state`)中传的`state`务必保证一致~~
|
||||
|
||||
## 升级到1.9.3+版本后编译失败
|
||||
|
||||
主要明显的就是`IpUtils.getIp`和request的`.state`报错。
|
||||
|
||||
这是因为从`v1.9.3`版本开始,对项目进行了一些优化,具体优化内容参考:[v1.9.3](https://gitee.com/yadong.zhang/JustAuth/releases/v1.9.3)和[v1.9.4](https://gitee.com/yadong.zhang/JustAuth/releases/v1.9.4)。
|
||||
|
||||
新版本的使用方式,参考[JustAuth-demo](https://gitee.com/yadong.zhang/JustAuth-demo/blob/master/src/main/java/me/zhyd/justauth/RestAuthController.java)
|
||||
```
|
||||
@RequestMapping("/render/{source}")
|
||||
public void renderAuth(@PathVariable("source") String source, HttpServletResponse response) throws IOException {
|
||||
AuthRequest authRequest = getAuthRequest(source);
|
||||
String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
|
||||
response.sendRedirect(authorizeUrl);
|
||||
}
|
||||
@RequestMapping("/callback/{source}")
|
||||
public Object login(@PathVariable("source") String source, AuthCallback callback) {
|
||||
AuthRequest authRequest = getAuthRequest(source);
|
||||
AuthResponse response = authRequest.login(callback);
|
||||
return response;
|
||||
}
|
||||
```
|
||||
|
||||
## 升级到最新版本后为什么支付宝登录不能用了?
|
||||
|
||||
在升级到新版后,使用支付宝登录会提示`ClassNotFoundExcption`异常,这是因为从`1.9.4`版本开始,JustAuth将不在强依赖`alipay-sdk-java`,如果你需要用到Alipay的授权登陆,那么你还需要添加以下依赖:
|
||||
|
||||
```
|
||||
<dependency>
|
||||
<groupId>com.alipay.sdk</groupId>
|
||||
<artifactId>alipay-sdk-java</artifactId>
|
||||
<version>3.7.4.ALL</version>
|
||||
</dependency>
|
||||
```
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
<p align="center">
|
||||
<a href="https://www.justauth.cn/"><img src="./_media/cover.png" width="400"></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<strong>Login, so easy!</strong>
|
||||
</p>
|
||||
<p align="center">
|
||||
<strong>史上最全的整合第三方登录的开源库</strong>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a target="_blank" href="https://search.maven.org/search?q=JustAuth">
|
||||
<img src="https://img.shields.io/badge/Maven Central-1.10.1-blue.svg" ></img>
|
||||
</a>
|
||||
<a target="_blank" href="https://gitee.com/yadong.zhang/JustAuth/blob/master/LICENSE">
|
||||
<img src="https://img.shields.io/apm/l/vim-mode.svg?color=yellow" ></img>
|
||||
</a>
|
||||
<a target="_blank" href="https://www.oracle.com/technetwork/java/javase/downloads/index.html">
|
||||
<img src="https://img.shields.io/badge/JDK-1.8+-green.svg" ></img>
|
||||
</a>
|
||||
<a target="_blank" href="https://apidoc.gitee.com/yadong.zhang/JustAuth/" title="API文档">
|
||||
<img src="https://img.shields.io/badge/Api Docs-1.10.1-orange.svg" ></img>
|
||||
</a>
|
||||
<a target="_blank" href="https://docs.justauth.whnb.wang" title="参考文档">
|
||||
<img src="https://img.shields.io/badge/Docs-latest-blueviolet.svg" ></img>
|
||||
</a>
|
||||
<a href="https://codecov.io/gh/zhangyd-c/JustAuth">
|
||||
<img src="https://codecov.io/gh/zhangyd-c/JustAuth/branch/master/graph/badge.svg" />
|
||||
</a>
|
||||
<a href='https://gitee.com/yadong.zhang/JustAuth/stargazers'>
|
||||
<img src='https://gitee.com/yadong.zhang/JustAuth/badge/star.svg?theme=white' alt='star'></img>
|
||||
</a>
|
||||
<a target="_blank" href='https://github.com/zhangyd-c/JustAuth'>
|
||||
<img src="https://img.shields.io/github/stars/zhangyd-c/JustAuth.svg?style=social" alt="github star"></img>
|
||||
</a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<strong>开源地址:</strong> <a target="_blank" href='https://gitee.com/yadong.zhang/JustAuth'>Gitee</a> | <a target="_blank" href='https://github.com/zhangyd-c/JustAuth'>Github</a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<strong>QQ群:</strong>230017570
|
||||
</p>
|
||||
<p align="center">
|
||||
<strong>文档更新日期:</strong> {docsify-updated}
|
||||
</p>
|
||||
|
||||
## 简介
|
||||
|
||||
JustAuth,如你所见,它仅仅是一个**第三方授权登录**的**工具类库**,它可以让我们脱离繁琐的第三方登录SDK,让登录变得**So easy!**
|
||||
|
||||
## 特点
|
||||
|
||||
废话不多说,就俩字:
|
||||
|
||||
1. **全**:已集成十多家第三方平台(国内外常用的基本都已包含),后续依然还有扩展计划!
|
||||
2. **简**:API就是奔着最简单去设计的,尽量让您用起来没有障碍感!
|
||||
|
||||
## 已集成的平台
|
||||
|
||||
| :computer: 平台 | :coffee: API类 | :page_facing_up: SDK |
|
||||
|:------:|:-------:|:-------:|
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/gitee.png" width="20"> | [AuthGiteeRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthGiteeRequest.java) | <a href="https://gitee.com/api/v5/oauth_doc#list_1" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/github.png" width="20"> | [AuthGithubRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthGiteeRequest.java) | <a href="https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/weibo.png" width="20"> | [AuthWeiboRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthGiteeRequest.java) | <a href="https://open.weibo.com/wiki/%E6%8E%88%E6%9D%83%E6%9C%BA%E5%88%B6%E8%AF%B4%E6%98%8E" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/dingtalk.png" width="20"> | [AuthDingTalkRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthDingTalkRequest.java) | <a href="https://open-doc.dingtalk.com/microapp/serverapi2/kymkv6" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/baidu.png" width="20"> | [AuthBaiduRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthBaiduRequest.java) | <a href="http://developer.baidu.com/wiki/index.php?title=docs/oauth" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/coding.png" width="25"> | [AuthCodingRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthCodingRequest.java) | <a href="https://open.coding.net/references/oauth/" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/tencentCloud.png" width="25"> | [AuthTencentCloudRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthTencentCloudRequest.java) | <a href="https://dev.tencent.com/help/doc/faq/b4e5b7aee786/oauth" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/oschina.png" width="20"> | [AuthOschinaRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthOschinaRequest.java) | <a href="https://www.oschina.net/openapi/docs/oauth2_authorize" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/alipay.png" width="20"> | [AuthAlipayRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthAlipayRequest.java) | <a href="https://alipay.open.taobao.com/docs/doc.htm?spm=a219a.7629140.0.0.336d4b70GUKXOl&treeId=193&articleId=105809&docType=1" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/qq.png" width="20"> | [AuthQqRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthQqRequest.java) | <a href="https://wiki.connect.qq.com/%E4%BD%BF%E7%94%A8authorization_code%E8%8E%B7%E5%8F%96access_token" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/wechat.png" width="20"> | [AuthWeChatRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthWeChatRequest.java) | <a href="https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/taobao.png" width="20"> | [AuthTaobaoRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthTaobaoRequest.java) | <a href="https://open.taobao.com/doc.htm?spm=a219a.7386797.0.0.4e00669acnkQy6&source=search&docId=105590&docType=1" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/google.png" width="20"> | [AuthGoogleRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthGoogleRequest.java) | <a href="https://developers.google.com/identity/protocols/OpenIDConnect" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/facebook.png" width="20"> | [AuthFacebookRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthFacebookRequest.java) | <a href="https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/douyin.png" width="20"> | [AuthDouyinRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthDouyinRequest.java) | <a href="https://www.douyin.com/platform/doc/m-2-1-1" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/linkedin.png" width="20"> | [AuthLinkedinRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthLinkedinRequest.java) | <a href="https://docs.microsoft.com/zh-cn/linkedin/shared/authentication/authorization-code-flow?context=linkedin/context" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/microsoft.png" width="20"> | [AuthMicrosoftRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthMicrosoftRequest.java) | <a href="https://docs.microsoft.com/zh-cn/graph/auth/" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/mi.png" width="20"> | [AuthMiRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthMiRequest.java) | <a href="https://dev.mi.com/console/doc/detail?pId=711" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/toutiao.png" width="20"> | [AuthToutiaoRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthToutiaoRequest.java) | <a href="https://open.mp.toutiao.com/#/resource?_k=y7mfgk" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/teambition.png" width="20"> | [AuthTeambitionRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthTeambitionRequest.java) | <a href="https://docs.teambition.com/" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/renren.png" width="20"> | [AuthRenrenRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthRenrenRequest.java) | <a href="http://open.renren.com/wiki/OAuth2.0" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/pinterest.png" width="20"> | [AuthPinterestRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthPinterestRequest.java) | <a href="https://developers.pinterest.com/docs/api/overview/?" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/stackoverflow.png" width="20"> | [AuthStackOverflowRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthStackOverflowRequest.java) | <a href="https://api.stackexchange.com/docs/authentication" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/huawei.png" width="20"> | [AuthHuaweiRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthHuaweiRequest.java) | <a href="https://developer.huawei.com/consumer/cn/devservice/doc/30101" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/wechat.png" width="20"> | [AuthWeChatEnterpriseRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthWeChatEnterpriseRequest.java) | <a href="https://open.work.weixin.qq.com/api/doc#90000/90135/90664" target="_blank">参考文档</a> |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/csdn.png" width="20"> | [AuthCsdnRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthCsdnRequest.java) | 无 |
|
||||
|
||||
|
||||
## 快速开始
|
||||
|
||||
- 引入依赖
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>me.zhyd.oauth</groupId>
|
||||
<artifactId>JustAuth</artifactId>
|
||||
<version>1.10.1</version>
|
||||
</dependency>
|
||||
```
|
||||
- 调用api
|
||||
```java
|
||||
// 创建授权request
|
||||
AuthRequest authRequest = new AuthGiteeRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.build());
|
||||
// 生成授权页面
|
||||
authRequest.authorize();
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的参数
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
authRequest.login(callback);
|
||||
```
|
||||
|
||||
## 贡献代码
|
||||
|
||||
1. fork本项目到自己的repo
|
||||
2. 把fork过去的项目也就是你仓库中的项目clone到你的本地
|
||||
3. 修改代码
|
||||
4. commit后push到自己的库
|
||||
5. 发起PR(pull request) 请求,提交到`dev`分支
|
||||
6. 等待作者合并
|
||||
|
||||
_注:JustAuth只接受集成oauth2.0的平台_
|
||||
|
||||
## 关于功能尝鲜
|
||||
|
||||
JustAuth一共有两个主要分支:
|
||||
- 线上版分支(master):稳定版,发布版就是这个分支的代码
|
||||
- 开发版分支(dev):不保证稳定,新功能都会优先推送到该分支,对于想尝鲜的朋友,可以直接下载代码,然后源码编译dev分支
|
||||
|
||||
|
||||
## 捐赠
|
||||
|
||||
| 支付宝 | 微信 |
|
||||
| :------------: | :------------: |
|
||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/qrcode/zfb_code.png" width="200"/> | <img src="https://gitee.com/yadong.zhang/static/raw/master/qrcode/wx_code.png" width="200" /> |
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||

|
||||
# JustAuth <small>1.10.1</small>
|
||||
|
||||
<strong>史上最全的整合第三方登录的开源库</strong>
|
||||
|
||||
<strong>Login, so easy</strong>
|
||||
|
||||
<p>已集成国内外十多家平台</p>
|
||||
<p>极简的API设计</p>
|
||||
|
||||
|
||||
[Gitee](https://gitee.com/yadong.zhang/JustAuth)
|
||||
[Github](https://github.com/zhangyd-c/JustAuth)
|
||||
[Get Started](#简介)
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,12 @@
|
||||
- [入门](README.md)
|
||||
- [更新记录](update.md)
|
||||
- 引导
|
||||
- [如何使用JustAuth集成一个平台](how-to-use.md)
|
||||
- [获取授权链接](authorize.md)
|
||||
- [登录](login.md)
|
||||
- 其他特性
|
||||
- [使用State](using-state.md)
|
||||
- [自定义state缓存](customize-the-state-cache.md)
|
||||
- [配套项目](supporting.md)
|
||||
- [Q&A](Q&A.md)
|
||||
- [Who is using](users.md)
|
||||
@@ -0,0 +1,3 @@
|
||||
# 获取授权链接
|
||||
|
||||
待补充
|
||||
@@ -0,0 +1,3 @@
|
||||
# 自定义state缓存
|
||||
|
||||
待补充
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1021 B |
@@ -0,0 +1,3 @@
|
||||
# 如何使用JustAuth集成一个平台
|
||||
|
||||
待补充
|
||||
@@ -0,0 +1,55 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>JustAuth - 史上最全的整合第三方登录的开源库</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
|
||||
<meta name="description" content="JustAuth,史上最全的整合第三方登录的开源库" />
|
||||
<meta name="keywords" content="JustAuth,第三方授权登录,OAuth" />
|
||||
|
||||
<meta itemprop="name" content="JustAuth,史上最全的整合第三方登录的开源库" />
|
||||
<meta itemprop="description" content="JustAuth,如你所见,它仅仅是一个第三方授权登录的工具类库,它可以让我们脱离繁琐的第三方登录SDK,让登录变得So easy!" />
|
||||
<meta itemprop="image" content="./_media/cover.png" />
|
||||
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css">
|
||||
<!-- 百度统计 -->
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?4c7a1a462477545b480a3dd1ed95f0a9";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">Please wait...</div>
|
||||
<script>
|
||||
window.$docsify = {
|
||||
name: '<img src="./_media/cover.png" width="200"><br>Login, so easy',
|
||||
search: {
|
||||
maxAge: 86400000,
|
||||
noData: {
|
||||
'/': '找不到结果'
|
||||
},
|
||||
paths: 'auto',
|
||||
placeholder: {
|
||||
'/': '搜索'
|
||||
}
|
||||
},
|
||||
repo: 'https://gitee.com/yadong.zhang/JustAuth',
|
||||
loadSidebar: true,
|
||||
maxLevel: 4,
|
||||
subMaxLevel: 2,
|
||||
auto2top: true,
|
||||
coverpage: true,
|
||||
formatUpdated: '{YYYY}/{MM}/{DD} {HH}:{mm}:{ss}',
|
||||
}
|
||||
</script>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,3 @@
|
||||
# 登录
|
||||
|
||||
待补充
|
||||
@@ -0,0 +1,8 @@
|
||||
## 配套demo
|
||||
- [Springboot版](https://gitee.com/yadong.zhang/JustAuth-demo) :JustAuth项目的demo(springboot项目)
|
||||
- [jFinal版](https://github.com/xkcoding/jfinal-justauth-demo) :Jfinal集成JustAuth的demo
|
||||
- [ActFramework版](https://github.com/xkcoding/act-justauth-demo) :ActFramework 集成 JustAuth 的 demo
|
||||
|
||||
## 插件
|
||||
- [justauth-spring-boot-starter](https://github.com/xkcoding/justauth-spring-boot-starter) :Spring Boot 集成 JustAuth 的最佳实践
|
||||
|
||||
+113
-20
@@ -1,10 +1,80 @@
|
||||
### 2019/07/19
|
||||
## v1.10.1
|
||||
### 2019/08/17
|
||||
|
||||
- AuthUser添加构造函数,支持反序列化
|
||||
|
||||
### 2019/08/08
|
||||
|
||||
- 项目迁移到组织[justauth](https://github.com/justauth)
|
||||
|
||||
## v1.10.0
|
||||
### 2019/08/06
|
||||
|
||||
- 合并[PR-34](https://github.com/zhangyd-c/JustAuth/pull/34),添加StringUtil单元测试,修复bug
|
||||
- 合并[PR-35](https://github.com/zhangyd-c/JustAuth/pull/35),集成企业微信
|
||||
|
||||
### 2019/08/05
|
||||
|
||||
- 集成华为登录
|
||||
- 修改`AuthChecker#checkCode`方法,对于不同平台使用不同参数接受code的情况统一做处理
|
||||
|
||||
### 2019/08/03
|
||||
|
||||
合并github上[xkcoding](https://github.com/xkcoding) 的[pr#32](https://github.com/zhangyd-c/JustAuth/pull/32),抽取 cache 接口,方便用户自行集成 cache
|
||||
|
||||
### 2019/08/02
|
||||
|
||||
- 增加`AuthCache`配置类`AuthCacheConfig.java`,可以自定义缓存有效期以及是否开启定时任务
|
||||
- 去掉`slf4j`依赖,封装`Log.java`工具类
|
||||
- 规范测试类
|
||||
|
||||
## v1.9.5
|
||||
### 2019/07/31
|
||||
|
||||
`v1.9.4`版本发布失败,请升级到`1.9.5`版本!
|
||||
|
||||
由此给您带来的不便,敬请谅解!
|
||||
|
||||
## v1.9.4
|
||||
### 2019/07/30
|
||||
|
||||
1. 升级`hutool-http`版本到`v4.6.1`
|
||||
2. 去除`AuthCallback`中增加的默认的校验state的方法,挪到`AuthDefaultRequest`中做统一处理
|
||||
3. `alipay-sdk-java`依赖改为`provided`,如果需要使用支付宝登录,需要使用方手动引入相关依赖,具体操作方式,见项目WIKI;
|
||||
4. 规范注释
|
||||
|
||||
## v1.9.3
|
||||
### 2019/07/30
|
||||
|
||||
1. 规范注释
|
||||
2. 增加State缓存,`AuthCallback`中增加默认的校验state的方法
|
||||
3. 增加默认的state生成方法,参考`AuthStateUtils.java`和`UuidUtils.java`
|
||||
4. 升级`hutool-http`版本到`v4.6.0`
|
||||
5. 修复其他一些问题
|
||||
|
||||
### 2019/07/27
|
||||
|
||||
1. `IpUtils.getIp`改名为`IpUtils.getLocalIp`
|
||||
2. 规范注释
|
||||
|
||||
### 2019/07/25
|
||||
|
||||
1. `AuthConfig`类中去掉state参数
|
||||
2. 删除`AuthState`类
|
||||
3. 增加`authorize(String)`方法,并且使用`@Deprecated`标记`authorize()`方法
|
||||
|
||||
## v1.9.2
|
||||
### 2019/07/22
|
||||
1. 合并github上[xkcoding](https://github.com/xkcoding) 的[pr#26](https://github.com/zhangyd-c/JustAuth/pull/26),AuthConfig类添加lombok注解,方便 [justauth-spring-boot-starter](https://github.com/xkcoding/justauth-spring-boot-starter) 直接使用
|
||||
|
||||
## v1.9.1
|
||||
### 2019/07/22
|
||||
1. 增加`stackoverflow`参数校验
|
||||
2. 解决`Pinterest`获取用户失败的问题
|
||||
3. 添加注释
|
||||
|
||||
### 2019/07/19
|
||||
## v1.9.0
|
||||
### 2019/07/19
|
||||
|
||||
1. 合并github上[@dyc12ii](https://github.com/dyc12ii) 的[pr#25](https://github.com/zhangyd-c/JustAuth/pull/25),升级fastjson版本至1.2.58,避免安全漏洞
|
||||
2. `AuthUserGender`枚举类挪到`enums`包下
|
||||
@@ -32,31 +102,40 @@
|
||||
2. 将CSDN相关的类置为`Deprecated`,后续可能会删除,也可能一直保留。毕竟CSDN的openAPI已经不对外开放了。
|
||||
3. `BaseAuthRequest` 改名为 `AuthDefaultRequest`
|
||||
4. `ResponseStatus` 改名为 `AuthResponseStatus` 并且移动到 `me.zhyd.oauth.model`
|
||||
5. 合并github上[@xkcoding](https://github.com/xkcoding) 的[pr#18](https://github.com/zhangyd-c/JustAuth/pull/18),修复小米回调错误问题 同时 支持微信获取
|
||||
5. 合并github上[@xkcoding](https://github.com/xkcoding) 的[pr#18](https://github.com/zhangyd-c/JustAuth/pull/18),修复小米回调错误问题 同时 支持微信获取unionId
|
||||
|
||||
### 2019/07/15
|
||||
## v1.8.1
|
||||
### 2019/07/15
|
||||
1. 新增 `AuthState` 类,内置默认的state生成规则和校验规则
|
||||
|
||||
### 2019/07/12
|
||||
1. 合并[Braavos96](https://github.com/Braavos96)提交的[PR#16](https://github.com/zhangyd-c/JustAuth/pull/16)
|
||||
|
||||
### 2019/06/28
|
||||
## v1.8.0
|
||||
### 2019/06/28
|
||||
1. 修复百度登录获取不到token失效时间的问题
|
||||
2. 增加state参数校验,预防CSRF。**强烈建议启用state**!
|
||||
|
||||
### 2019/06/27
|
||||
1. 修改login方法的参数为AuthCallback,封装回调返回的参数
|
||||
2. 支持state参数
|
||||
3. 增加code和state参数校验
|
||||
1. 修复百度登录获取不到token失效时间的问题
|
||||
2. 增加state参数校验,预防CSRF。**强烈建议启用state**!
|
||||
3. 修改login方法的参数为AuthCallback,封装回调返回的参数
|
||||
4. 支持state参数
|
||||
5. 增加code和state参数校验
|
||||
|
||||
### 2019/06/25
|
||||
由于state安全问题,1.8.0以前的版本都有隐藏的CSRF漏洞问题,所以强烈建议正在使用JustAuth的朋友升级到1.8.0版本!
|
||||
|
||||
## v1.7.1
|
||||
### 2019/06/25
|
||||
qq授权登录时,需要获取`openId`作为`uuid`,在`1.6.1-beta`和`1.7.0`版本中,引入了`unionId`这一属性。获取`unionid`需要单独向qq团队**发送邮件**申请权限,鉴于这一申请权限的步骤比较麻烦(需要填写的内容比较多),所以在`AuthConfig`中增加了一个`unionId`属性,当为**true**时才会获取unionid,当为false时只获取openId。如果你需要该功能, 则在自行申请了相关权限后,将该属性置为true即可。关于unionId的参考链接:[UnionID介绍](http://wiki.connect.qq.com/unionid%E4%BB%8B%E7%BB%8D)
|
||||
|
||||
### 2019/06/19
|
||||
## v1.7.0
|
||||
### 2019/06/19
|
||||
1. 合并[xkcoding](https://github.com/xkcoding)提交的[PR](https://github.com/zhangyd-c/JustAuth/pull/14),重构了部分代码,jar包由原来的`130+kb`优化到现在的`110+kb`
|
||||
2. 合并[skqing](https://gitee.com/skqing)提交的[PR](https://gitee.com/yadong.zhang/JustAuth/pulls/3), 解决抖音登录失败问题
|
||||
|
||||
### 2019/06/18
|
||||
## v1.6.1-beta
|
||||
### 2019/06/18
|
||||
1. 解决Issue [#IY2HW](https://gitee.com/yadong.zhang/JustAuth/issues/IY2HW)
|
||||
2. 解决Issue [#IY2OH](https://gitee.com/yadong.zhang/JustAuth/issues/IY2OH)
|
||||
3. 解决Issue [#IY2FV](https://gitee.com/yadong.zhang/JustAuth/issues/IY2FV)
|
||||
@@ -64,38 +143,44 @@ qq授权登录时,需要获取`openId`作为`uuid`,在`1.6.1-beta`和`1.7.0`
|
||||
5. 解决Issue [#IY1QR](https://gitee.com/yadong.zhang/JustAuth/issues/IY1QR) 增加对Config属性的校验功能,主要校验redirect uri的合法性
|
||||
6. 合并[skqing](https://gitee.com/skqing)提交的[PR](https://gitee.com/yadong.zhang/JustAuth/pulls/2),解决一些BUG
|
||||
|
||||
### 2019/06/06
|
||||
## v1.6.0-beta
|
||||
### 2019/06/06
|
||||
1. 增加今日头条的授权登陆
|
||||
2. 发布1.6.0-beta版本,今日头条开发者暂时不能认证, 所以无法做测试,等测试通过后,正式发布release版本
|
||||
|
||||
### 2019/05/28
|
||||
## v1.5.0
|
||||
### 2019/05/28
|
||||
1. 增加小米账号和微软的授权登陆
|
||||
2. 发布1.5.0版本
|
||||
|
||||
### 2019/05/26
|
||||
## v1.4.0
|
||||
### 2019/05/26
|
||||
1. 增加抖音和Linkedin的授权登陆
|
||||
2. 修改部分图片命名
|
||||
3. 优化部分代码
|
||||
4. 修复`AuthSource`中腾讯云开发平台的拼写错误:`TENCEN_CLOUD`->`TENCENT_CLOUD`
|
||||
5. 修复支付宝登陆时用户名为空的问题
|
||||
|
||||
|
||||
### 2019/05/24
|
||||
## v1.3.3
|
||||
### 2019/05/24
|
||||
1. 修复一些问题
|
||||
2. 升级api,在AuthUser中增加`uuid`属性,可以通过`uuid` + `source`唯一确定一个用户,此举解决了用户身份归属的问题。
|
||||
3. 发布1.3.3版本的jar包到公开仓库(1.3.2忘记发布了,( ╯□╰ ))
|
||||
4. 重要:经咨询官方客服得知,CSDN的授权开放平台已经下线,如果以前申请过的应用,可以继续使用,但是不再支持申请新的应用。so, 本项目中的CSDN登录只能针对少部分用户使用了
|
||||
|
||||
### 2019/05/23
|
||||
## v1.3.1
|
||||
### 2019/05/23
|
||||
1. 修复QQ登录的问题
|
||||
2. 发布1.3.1版本的jar包到公开仓库
|
||||
|
||||
### 2019/05/21
|
||||
## v1.3.0
|
||||
### 2019/05/21
|
||||
1. 新增google授权登录
|
||||
2. 新增facebook授权登录
|
||||
3. 发布1.3.0版本的jar包到公开仓库
|
||||
|
||||
### 2019/05/18
|
||||
## v1.1.0
|
||||
### 2019/05/18
|
||||
1. 发布1.1.0版本的jar包到公开仓库(支持qq和微信登录)
|
||||
2. 支持淘宝登录
|
||||
3. 修改`AuthUser.java`类中的`accessToken`属性,由原本的~~accessToken (String)~~改为`token (AuthToken)`
|
||||
@@ -104,4 +189,12 @@ qq授权登录时,需要获取`openId`作为`uuid`,在`1.6.1-beta`和`1.7.0`
|
||||
|
||||
### 2019/05/17
|
||||
1. 增加qq和微信的授权登录
|
||||
2. 修改getAccessToken方法的返回值
|
||||
2. 修改getAccessToken方法的返回值
|
||||
|
||||
## v1.0.1
|
||||
### 2019/03/27
|
||||
集成 支付宝授权登录
|
||||
|
||||
## v1.0.0
|
||||
### 2019/03/25
|
||||
史上最全的整合第三方登录的工具,目前已支持Github、Gitee、微博、钉钉和百度、Coding、腾讯云开发者平台和OSChina登录。 Login, so easy!
|
||||
@@ -0,0 +1,11 @@
|
||||
# Who is using?
|
||||
|
||||
- [spring-boot-demo](https://github.com/xkcoding/spring-boot-demo): spring boot demo 是一个用来学习 spring boot 的项目,总共包含 55 个集成demo,已经完成 46 个。(注:[spring-boot-demo-social](https://github.com/xkcoding/spring-boot-demo/tree/master/spring-boot-demo-social)模块中集成了JustAuth)注:该作者是JustAuth的开发者之一,负责开发QQ登录、微信登录、小米登录、微软登录、谷歌登录。
|
||||
- [Guns](https://gitee.com/stylefeng/guns): Guns基于Spring Boot2,致力于做更简洁的后台管理系统。(注:Guns企业版中使用到了JustAuth实现第三方OAuth登录)
|
||||
|
||||
- [Shiro-Action](https://github.com/zhaojun1998/Shiro-Action): 基于 Shiro 的权限管理系统,支持 restful url 授权
|
||||
- [project-template](https://github.com/HobbyBear/project-template): 作为前后端分离项目的后端模板整个项目基于springboot2.1.3,集jsr303框架做参数校验,spring security 做权限管理,并实现限制同一账号登陆会话数量功能,spring mail 发送邮件,justAuth做的第三方登陆, spring session做session共享,orm框架采用jpa,集成七牛云实现图片上传,redis实现分布式锁
|
||||
- [mica](https://github.com/lets-mica/mica/tree/master/mica-social):mica是Spring Cloud 微服务开发核心包。采用源码形式(保留了作者名)另加改了一些代码。
|
||||
...
|
||||
|
||||
我在这儿等你 >>> :alien:
|
||||
@@ -0,0 +1,3 @@
|
||||
# 使用State
|
||||
|
||||
待补充
|
||||
@@ -2,192 +2,264 @@
|
||||
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>me.zhyd.oauth</groupId>
|
||||
<artifactId>JustAuth</artifactId>
|
||||
<version>1.9.1</version>
|
||||
<groupId>me.zhyd.oauth</groupId>
|
||||
<artifactId>JustAuth</artifactId>
|
||||
<version>1.10.1</version>
|
||||
|
||||
<name>JustAuth</name>
|
||||
<name>JustAuth</name>
|
||||
<url>https://gitee.com/yadong.zhang/JustAuth</url>
|
||||
<description>
|
||||
史上最全的整合第三方登录的工具,目前已支持Github、Gitee、微博、钉钉、百度、Coding、腾讯云开发者平台、OSChina、支付宝、QQ、微信、淘宝、Google、Facebook、抖音、领英、小米、微软和今日头条等第三方平台的授权登录。
|
||||
Login, so easy!
|
||||
</description>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>MIT</name>
|
||||
<url>https://gitee.com/yadong.zhang/JustAuth/blob/master/LICENSE</url>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:https://gitee.com/yadong.zhang/JustAuth.git</connection>
|
||||
<developerConnection>scm:git:https://gitee.com/yadong.zhang/JustAuth.git</developerConnection>
|
||||
<url>https://gitee.com/yadong.zhang/JustAuth</url>
|
||||
<description>
|
||||
史上最全的整合第三方登录的工具,目前已支持Github、Gitee、微博、钉钉、百度、Coding、腾讯云开发者平台、OSChina、支付宝、QQ、微信、淘宝、Google、Facebook、抖音、领英、小米、微软和今日头条等第三方平台的授权登录。
|
||||
Login, so easy!
|
||||
</description>
|
||||
</scm>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>MIT</name>
|
||||
<url>https://gitee.com/yadong.zhang/JustAuth/blob/master/LICENSE</url>
|
||||
</license>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer>
|
||||
<name>Yadong.Zhang</name>
|
||||
<email>yadong.zhang0415@gmail.com</email>
|
||||
<url>https://www.zhyd.me</url>
|
||||
</developer>
|
||||
<developer>
|
||||
<name>Yangkai.Shen</name>
|
||||
<email>shenyangkai1994@gmail.com</email>
|
||||
<url>https://xkcoding.com</url>
|
||||
</developer>
|
||||
<developer>
|
||||
<name>Hongwei.Peng</name>
|
||||
<email>pengisgood@gmail.com</email>
|
||||
<url>https://github.com/pengisgood</url>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:https://gitee.com/yadong.zhang/JustAuth.git</connection>
|
||||
<developerConnection>scm:git:https://gitee.com/yadong.zhang/JustAuth.git</developerConnection>
|
||||
<url>https://gitee.com/yadong.zhang/JustAuth</url>
|
||||
</scm>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<maven-source.version>2.2.1</maven-source.version>
|
||||
<maven-compiler.version>3.8.1</maven-compiler.version>
|
||||
<maven-javadoc.version>3.1.0</maven-javadoc.version>
|
||||
<cobertura-version>2.7</cobertura-version>
|
||||
<maven-surefire-version>2.20</maven-surefire-version>
|
||||
<maven-gpg-version>1.6</maven-gpg-version>
|
||||
<maven.test.skip>false</maven.test.skip>
|
||||
<hutool-version>4.6.1</hutool-version>
|
||||
<lombok-version>1.18.4</lombok-version>
|
||||
<junit-version>4.11</junit-version>
|
||||
<fastjson-version>1.2.58</fastjson-version>
|
||||
<alipay-sdk-version>3.7.4.ALL</alipay-sdk-version>
|
||||
<jacoco-version>0.8.2</jacoco-version>
|
||||
</properties>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<name>Yadong.Zhang</name>
|
||||
<email>yadong.zhang0415@gmail.com</email>
|
||||
<url>https://www.zhyd.me</url>
|
||||
</developer>
|
||||
<developer>
|
||||
<name>Yangkai.Shen</name>
|
||||
<email>shenyangkai1994@gmail.com</email>
|
||||
<url>https://xkcoding.com</url>
|
||||
</developer>
|
||||
<developer>
|
||||
<name>Hongwei.Peng</name>
|
||||
<email>pengisgood@gmail.com</email>
|
||||
<url>https://github.com/pengisgood</url>
|
||||
</developer>
|
||||
</developers>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok-version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-http</artifactId>
|
||||
<version>${hutool-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alipay.sdk</groupId>
|
||||
<artifactId>alipay-sdk-java</artifactId>
|
||||
<version>${alipay-sdk-version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<maven-source.version>2.2.1</maven-source.version>
|
||||
<maven-compiler.version>3.7.0</maven-compiler.version>
|
||||
<maven.test.skip>true</maven.test.skip>
|
||||
<hutool-version>4.5.15</hutool-version>
|
||||
<lombok-version>1.18.4</lombok-version>
|
||||
<junit-version>4.11</junit-version>
|
||||
<fastjson-version>1.2.58</fastjson-version>
|
||||
<alipay-sdk-version>3.7.4.ALL</alipay-sdk-version>
|
||||
<slf4j-version>1.7.25</slf4j-version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-http</artifactId>
|
||||
<version>${hutool-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alipay.sdk</groupId>
|
||||
<artifactId>alipay-sdk-java</artifactId>
|
||||
<version>${alipay-sdk-version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<version>${slf4j-version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>${project.artifactId}-${project.version}</finalName>
|
||||
<build>
|
||||
<finalName>${project.artifactId}-${project.version}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler.version}</version>
|
||||
<configuration>
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>${maven-source.version}</version>
|
||||
<inherited>true</inherited>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>jar-no-fork</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>${maven-javadoc.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${maven-surefire-version}</version>
|
||||
<configuration>
|
||||
<!-- 包含其他测试类 -->
|
||||
<includes>
|
||||
<include>**/*Test.java</include>
|
||||
</includes>
|
||||
<!-- 排除掉AuthRequestTest测试类,该类只做api演示用 -->
|
||||
<excludes>
|
||||
<exclude>**/AuthRequestTest.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler.version}</version>
|
||||
<configuration>
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>${maven-source.version}</version>
|
||||
<inherited>true</inherited>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>jar-no-fork</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>${maven-source.version}</version>
|
||||
<inherited>true</inherited>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>jar-no-fork</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>${cobertura-version}</version>
|
||||
<configuration>
|
||||
<formats>
|
||||
<format>html</format>
|
||||
<format>xml</format>
|
||||
</formats>
|
||||
<check/>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>${jacoco-version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>report</id>
|
||||
<phase>test</phase>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>${maven-gpg-version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>${maven-source.version}</version>
|
||||
<inherited>true</inherited>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>jar-no-fork</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<distributionManagement>
|
||||
<snapshotRepository>
|
||||
<id>sonatype-nexus-snapshots</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
</snapshotRepository>
|
||||
<repository>
|
||||
<id>sonatype-nexus-staging</id>
|
||||
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
</profile>
|
||||
</profiles>
|
||||
</build>
|
||||
<distributionManagement>
|
||||
<snapshotRepository>
|
||||
<id>sonatype-nexus-snapshots</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
</snapshotRepository>
|
||||
<repository>
|
||||
<id>sonatype-nexus-staging</id>
|
||||
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
</profile>
|
||||
<!--私服-->
|
||||
<profile>
|
||||
<id>nexus</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>${maven-gpg-version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>xkcoding-nexus</id>
|
||||
<url>https://nexus.xkcoding.com/repository/maven-releases/</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>xkcoding-nexus</id>
|
||||
<url>https://nexus.xkcoding.com/repository/maven-snapshots/</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package me.zhyd.oauth.cache;
|
||||
|
||||
/**
|
||||
* JustAuth缓存,用来缓存State
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.9.3
|
||||
*/
|
||||
public interface AuthCache {
|
||||
|
||||
/**
|
||||
* 设置缓存
|
||||
*
|
||||
* @param key 缓存KEY
|
||||
* @param value 缓存内容
|
||||
*/
|
||||
void set(String key, String value);
|
||||
|
||||
/**
|
||||
* 设置缓存,指定过期时间
|
||||
*
|
||||
* @param key 缓存KEY
|
||||
* @param value 缓存内容
|
||||
* @param timeout 指定缓存过期时间(毫秒)
|
||||
*/
|
||||
void set(String key, String value, long timeout);
|
||||
|
||||
/**
|
||||
* 获取缓存
|
||||
*
|
||||
* @param key 缓存KEY
|
||||
* @return 缓存内容
|
||||
*/
|
||||
String get(String key);
|
||||
|
||||
/**
|
||||
* 是否存在key,如果对应key的value值已过期,也返回false
|
||||
*
|
||||
* @param key 缓存KEY
|
||||
* @return true:存在key,并且value没过期;false:key不存在或者已过期
|
||||
*/
|
||||
boolean containsKey(String key);
|
||||
|
||||
/**
|
||||
* 清理过期的缓存
|
||||
*/
|
||||
default void pruneCache() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package me.zhyd.oauth.cache;
|
||||
|
||||
/**
|
||||
* AuthCache配置类
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.10.0
|
||||
*/
|
||||
public class AuthCacheConfig {
|
||||
|
||||
/**
|
||||
* 默认缓存过期时间:3分钟
|
||||
* 鉴于授权过程中,根据个人的操作习惯,或者授权平台的不同(google等),每个授权流程的耗时也有差异,不过单个授权流程一般不会太长
|
||||
* 本缓存工具默认的过期时间设置为3分钟,即程序默认认为3分钟内的授权有效,超过3分钟则默认失效,失效后删除
|
||||
*/
|
||||
public static long timeout = 3 * 60 * 1000;
|
||||
|
||||
/**
|
||||
* 是否开启定时{@link AuthDefaultCache#pruneCache()}的任务
|
||||
*/
|
||||
public static boolean schedulePrune = true;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package me.zhyd.oauth.cache;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* 缓存调度器
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.9.3
|
||||
*/
|
||||
public enum AuthCacheScheduler {
|
||||
|
||||
/**
|
||||
* 当前实例
|
||||
*/
|
||||
INSTANCE;
|
||||
|
||||
private AtomicInteger cacheTaskNumber = new AtomicInteger(1);
|
||||
private ScheduledExecutorService scheduler;
|
||||
|
||||
AuthCacheScheduler() {
|
||||
create();
|
||||
}
|
||||
|
||||
private void create() {
|
||||
this.shutdown();
|
||||
this.scheduler = new ScheduledThreadPoolExecutor(10, r -> new Thread(r, String.format("JustAuth-Task-%s", cacheTaskNumber.getAndIncrement())));
|
||||
}
|
||||
|
||||
private void shutdown() {
|
||||
if (null != scheduler) {
|
||||
this.scheduler.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public void schedule(Runnable task, long delay) {
|
||||
this.scheduler.scheduleAtFixedRate(task, delay, delay, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package me.zhyd.oauth.cache;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
/**
|
||||
* 默认的缓存实现
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.9.3
|
||||
*/
|
||||
public class AuthDefaultCache implements AuthCache {
|
||||
|
||||
/**
|
||||
* state cache
|
||||
*/
|
||||
private static Map<String, CacheState> stateCache = new ConcurrentHashMap<>();
|
||||
private final ReentrantReadWriteLock cacheLock = new ReentrantReadWriteLock(true);
|
||||
private final Lock writeLock = cacheLock.writeLock();
|
||||
private final Lock readLock = cacheLock.readLock();
|
||||
|
||||
public AuthDefaultCache() {
|
||||
if (AuthCacheConfig.schedulePrune) {
|
||||
this.schedulePrune(AuthCacheConfig.timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置缓存
|
||||
*
|
||||
* @param key 缓存KEY
|
||||
* @param value 缓存内容
|
||||
*/
|
||||
@Override
|
||||
public void set(String key, String value) {
|
||||
set(key, value, AuthCacheConfig.timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置缓存
|
||||
*
|
||||
* @param key 缓存KEY
|
||||
* @param value 缓存内容
|
||||
* @param timeout 指定缓存过期时间(毫秒)
|
||||
*/
|
||||
@Override
|
||||
public void set(String key, String value, long timeout) {
|
||||
writeLock.lock();
|
||||
try {
|
||||
stateCache.put(key, new CacheState(value, timeout));
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存
|
||||
*
|
||||
* @param key 缓存KEY
|
||||
* @return 缓存内容
|
||||
*/
|
||||
@Override
|
||||
public String get(String key) {
|
||||
readLock.lock();
|
||||
try {
|
||||
CacheState cacheState = stateCache.get(key);
|
||||
if (null == cacheState || cacheState.isExpired()) {
|
||||
return null;
|
||||
}
|
||||
return cacheState.getState();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否存在key,如果对应key的value值已过期,也返回false
|
||||
*
|
||||
* @param key 缓存KEY
|
||||
* @return true:存在key,并且value没过期;false:key不存在或者已过期
|
||||
*/
|
||||
@Override
|
||||
public boolean containsKey(String key) {
|
||||
readLock.lock();
|
||||
try {
|
||||
CacheState cacheState = stateCache.get(key);
|
||||
return null != cacheState && !cacheState.isExpired();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理过期的缓存
|
||||
*/
|
||||
@Override
|
||||
public void pruneCache() {
|
||||
Iterator<CacheState> values = stateCache.values().iterator();
|
||||
CacheState cacheState;
|
||||
while (values.hasNext()) {
|
||||
cacheState = values.next();
|
||||
if (cacheState.isExpired()) {
|
||||
values.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时清理
|
||||
*
|
||||
* @param delay 间隔时长,单位毫秒
|
||||
*/
|
||||
public void schedulePrune(long delay) {
|
||||
AuthCacheScheduler.INSTANCE.schedule(this::pruneCache, delay);
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private class CacheState implements Serializable {
|
||||
private String state;
|
||||
private long expire;
|
||||
|
||||
CacheState(String state, long expire) {
|
||||
this.state = state;
|
||||
// 实际过期时间等于当前时间加上有效期
|
||||
this.expire = System.currentTimeMillis() + expire;
|
||||
}
|
||||
|
||||
boolean isExpired() {
|
||||
return System.currentTimeMillis() > this.expire;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package me.zhyd.oauth.cache;
|
||||
|
||||
/**
|
||||
* 默认的state缓存实现
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.10.0
|
||||
*/
|
||||
public enum AuthDefaultStateCache implements AuthStateCache {
|
||||
|
||||
/**
|
||||
* 当前实例
|
||||
*/
|
||||
INSTANCE;
|
||||
|
||||
private AuthCache authCache;
|
||||
|
||||
AuthDefaultStateCache() {
|
||||
authCache = new AuthDefaultCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* 存入缓存
|
||||
*
|
||||
* @param key 缓存key
|
||||
* @param value 缓存内容
|
||||
*/
|
||||
@Override
|
||||
public void cache(String key, String value) {
|
||||
authCache.set(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存入缓存
|
||||
*
|
||||
* @param key 缓存key
|
||||
* @param value 缓存内容
|
||||
* @param timeout 指定缓存过期时间(毫秒)
|
||||
*/
|
||||
@Override
|
||||
public void cache(String key, String value, long timeout) {
|
||||
authCache.set(key, value, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存内容
|
||||
*
|
||||
* @param key 缓存key
|
||||
* @return 缓存内容
|
||||
*/
|
||||
@Override
|
||||
public String get(String key) {
|
||||
return authCache.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否存在key,如果对应key的value值已过期,也返回false
|
||||
*
|
||||
* @param key 缓存key
|
||||
* @return true:存在key,并且value没过期;false:key不存在或者已过期
|
||||
*/
|
||||
@Override
|
||||
public boolean containsKey(String key) {
|
||||
return authCache.containsKey(key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package me.zhyd.oauth.cache;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* State缓存接口,方便用户扩展
|
||||
* </p>
|
||||
*
|
||||
* @author yangkai.shen
|
||||
* @since 1.10.0
|
||||
*/
|
||||
public interface AuthStateCache {
|
||||
/**
|
||||
* 存入缓存
|
||||
*
|
||||
* @param key 缓存key
|
||||
* @param value 缓存内容
|
||||
*/
|
||||
void cache(String key, String value);
|
||||
|
||||
/**
|
||||
* 存入缓存
|
||||
*
|
||||
* @param key 缓存key
|
||||
* @param value 缓存内容
|
||||
* @param timeout 指定缓存过期时间(毫秒)
|
||||
*/
|
||||
void cache(String key, String value, long timeout);
|
||||
|
||||
/**
|
||||
* 获取缓存内容
|
||||
*
|
||||
* @param key 缓存key
|
||||
* @return 缓存内容
|
||||
*/
|
||||
String get(String key);
|
||||
|
||||
/**
|
||||
* 是否存在key,如果对应key的value值已过期,也返回false
|
||||
*
|
||||
* @param key 缓存key
|
||||
* @return true:存在key,并且value没过期;false:key不存在或者已过期
|
||||
*/
|
||||
boolean containsKey(String key);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* JustAuth 缓存实现, 提供基础的基于ConcurrentHashMap + ScheduledExecutorService 实现的定时缓存。
|
||||
* 同时对外暴露{@code AuthStateCache}接口,可进行对缓存实现的自定义。
|
||||
*/
|
||||
package me.zhyd.oauth.cache;
|
||||
@@ -1,17 +1,18 @@
|
||||
package me.zhyd.oauth.config;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* JustAuth配置类
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AuthConfig {
|
||||
|
||||
/**
|
||||
@@ -43,17 +44,18 @@ public class AuthConfig {
|
||||
*/
|
||||
private boolean unionId;
|
||||
|
||||
/**
|
||||
* 一个神奇的参数,最好使用随机的不可测的内容,可以用来防止CSRF攻击
|
||||
* <p>
|
||||
* 1.8.0版本新增参数
|
||||
*/
|
||||
private String state;
|
||||
|
||||
/**
|
||||
* Stack Overflow Key
|
||||
* <p>
|
||||
* 1.9.0版本新增参数
|
||||
*
|
||||
* @since 1.9.0
|
||||
*/
|
||||
private String stackOverflowKey;
|
||||
|
||||
/**
|
||||
* 企业微信,授权方的网页应用ID
|
||||
*
|
||||
* @since 1.10.0
|
||||
*/
|
||||
private String agentId;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package me.zhyd.oauth.config;
|
||||
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.AuthResponseStatus;
|
||||
|
||||
/**
|
||||
* 各api需要的url, 用枚举类分平台类型管理
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.0
|
||||
*/
|
||||
public enum AuthSource {
|
||||
@@ -519,6 +518,55 @@ public enum AuthSource {
|
||||
public String userInfo() {
|
||||
return "https://api.stackexchange.com/2.2/me";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 华为
|
||||
*
|
||||
* @since 1.10.0
|
||||
*/
|
||||
HUAWEI {
|
||||
@Override
|
||||
public String authorize() {
|
||||
return "https://oauth-login.cloud.huawei.com/oauth2/v2/authorize";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String accessToken() {
|
||||
return "https://oauth-login.cloud.huawei.com/oauth2/v2/token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String userInfo() {
|
||||
return "https://api.vmall.com/rest.php";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String refresh() {
|
||||
return "https://oauth-login.cloud.huawei.com/oauth2/v2/token";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 企业微信
|
||||
*
|
||||
* @since 1.10.0
|
||||
*/
|
||||
WECHAT_ENTERPRISE {
|
||||
@Override
|
||||
public String authorize() {
|
||||
return "https://open.work.weixin.qq.com/wwopen/sso/qrConnect";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String accessToken() {
|
||||
return "https://qyapi.weixin.qq.com/cgi-bin/gettoken";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String userInfo() {
|
||||
return "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* JustAuth 核心配置相关,包括{@code AuthConfig}和{@code AuthSource}
|
||||
*/
|
||||
package me.zhyd.oauth.config;
|
||||
+7
-2
@@ -1,16 +1,21 @@
|
||||
package me.zhyd.oauth.model;
|
||||
package me.zhyd.oauth.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* JustAuth通用的状态码对照表
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum AuthResponseStatus {
|
||||
/**
|
||||
* 2000:正常;
|
||||
* other:调用异常,具体异常内容见{@code msg}
|
||||
*/
|
||||
SUCCESS(2000, "Success"),
|
||||
FAILURE(5000, "Failure"),
|
||||
NOT_IMPLEMENTED(5001, "Not Implemented"),
|
||||
@@ -7,12 +7,15 @@ import lombok.Getter;
|
||||
* 今日头条授权登录时的异常状态码
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum AuthToutiaoErrorCode {
|
||||
/**
|
||||
* 0:正常;
|
||||
* other:调用异常,具体异常内容见{@code desc}
|
||||
*/
|
||||
EC0(0, "接口调用成功"),
|
||||
EC1(1, "API配置错误,未传入Client Key"),
|
||||
EC2(2, "API配置错误,Client Key错误,请检查是否和开放平台的ClientKey一致"),
|
||||
|
||||
@@ -9,13 +9,19 @@ import java.util.Arrays;
|
||||
* 用户性别
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum AuthUserGender {
|
||||
MALE(1, "男"), FEMALE(0, "女"), UNKNOWN(-1, "未知");
|
||||
/**
|
||||
* MALE/FAMALE为正常值,通过{@link AuthUserGender#getRealGender(String)}方法获取真实的性别
|
||||
* UNKNOWN为容错值,部分平台不会返回用户性别,为了方便统一,使用UNKNOWN标记所有未知或不可测的用户性别信息
|
||||
*/
|
||||
MALE(1, "男"),
|
||||
FEMALE(0, "女"),
|
||||
UNKNOWN(-1, "未知");
|
||||
|
||||
private int code;
|
||||
private String desc;
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 提供一些必要的枚举类
|
||||
*/
|
||||
package me.zhyd.oauth.enums;
|
||||
@@ -1,10 +1,11 @@
|
||||
package me.zhyd.oauth.exception;
|
||||
|
||||
import me.zhyd.oauth.model.AuthResponseStatus;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
|
||||
/**
|
||||
* JustAuth通用异常类
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
*/
|
||||
public class AuthException extends RuntimeException {
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* JustAuth专用异常封装
|
||||
*/
|
||||
package me.zhyd.oauth.exception;
|
||||
@@ -0,0 +1,150 @@
|
||||
package me.zhyd.oauth.log;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* 针对JustAuth提供的轻量级的日志打印工具
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @see Log#debug(String)
|
||||
* @see Log#debug(String, Throwable)
|
||||
* @see Log#warn(String)
|
||||
* @see Log#warn(String, Throwable)
|
||||
* @see Log#error(String)
|
||||
* @see Log#error(String, Throwable)
|
||||
* @since 1.10.0
|
||||
*/
|
||||
public class Log {
|
||||
|
||||
public static void debug(String msg) {
|
||||
debug(msg, null);
|
||||
}
|
||||
|
||||
public static void warn(String msg) {
|
||||
warn(msg, null);
|
||||
}
|
||||
|
||||
public static void error(String msg) {
|
||||
error(msg, null);
|
||||
}
|
||||
|
||||
public static void debug(String msg, Throwable t) {
|
||||
print(Level.DEBUG, msg, t, System.out);
|
||||
}
|
||||
|
||||
public static void warn(String msg, Throwable t) {
|
||||
print(Level.WARN, msg, t, System.out);
|
||||
}
|
||||
|
||||
public static void error(String msg, Throwable t) {
|
||||
print(Level.ERROR, msg, t, System.err);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印日志内容,格式:2019-08-02 20:44:07 main me.zhyd.oauth.log.Log(debug:39) [DEBUG] - xxxx
|
||||
*
|
||||
* @param level 日志级别
|
||||
* @param msg 日志内容
|
||||
* @param t 异常信息
|
||||
* @param ps 实际执行打印的PrintStream
|
||||
*/
|
||||
private static void print(Level level, String msg, Throwable t, PrintStream ps) {
|
||||
if (Config.enable) {
|
||||
if (level.getLevelNum() >= Config.level.getLevelNum()) {
|
||||
ps.println(String.format("%s %s %s [%s] - %s", getDate(), Thread.currentThread().getName(), getCaller(), level, msg));
|
||||
writeThrowable(t, ps);
|
||||
ps.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取调用方的信息
|
||||
*
|
||||
* @return 返回调用方的信息,格式:class(method:lineNumber)
|
||||
*/
|
||||
private static String getCaller() {
|
||||
int offset = 2;
|
||||
StackTraceElement[] stackTraceArr = (new Throwable()).getStackTrace();
|
||||
StackTraceElement stackTrace = null;
|
||||
if (offset >= stackTraceArr.length) {
|
||||
offset = offset - 1;
|
||||
}
|
||||
stackTrace = stackTraceArr[offset];
|
||||
return stackTrace.getClassName() +
|
||||
"(" +
|
||||
stackTrace.getMethodName() +
|
||||
':' +
|
||||
stackTrace.getLineNumber() +
|
||||
")";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取格式化后的日期
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static String getDate() {
|
||||
return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印异常信息
|
||||
*
|
||||
* @param t 异常
|
||||
* @param targetStream 实际执行打印的PrintStream
|
||||
*/
|
||||
private static void writeThrowable(Throwable t, PrintStream targetStream) {
|
||||
if (t != null) {
|
||||
t.printStackTrace(targetStream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志级别
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.10.0
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum Level {
|
||||
/**
|
||||
* DEBUG: 普通级别
|
||||
*/
|
||||
DEBUG(10),
|
||||
/**
|
||||
* WARN: 警告级别
|
||||
*/
|
||||
WARN(30),
|
||||
/**
|
||||
* ERROR: 异常级别
|
||||
*/
|
||||
ERROR(40);
|
||||
|
||||
private int levelNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志配置
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.10.0
|
||||
*/
|
||||
static class Config {
|
||||
|
||||
/**
|
||||
* 需要打印的日志级别
|
||||
*/
|
||||
static Level level = Level.DEBUG;
|
||||
/**
|
||||
* 是否启用日志打印功能,默认启用
|
||||
*/
|
||||
static boolean enable = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 针对JustAuth简单封装的日志打印工具,可用过{@link me.zhyd.oauth.log.Log.Config}开关日志和指定日志级别
|
||||
*/
|
||||
package me.zhyd.oauth.log;
|
||||
@@ -7,8 +7,7 @@ import lombok.Setter;
|
||||
* 授权回调时的参数类
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.8.0
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@@ -28,4 +27,11 @@ public class AuthCallback {
|
||||
* 访问AuthorizeUrl后回调时带的参数state,用于和请求AuthorizeUrl前的state比较,防止CSRF攻击
|
||||
*/
|
||||
private String state;
|
||||
|
||||
/**
|
||||
* 华为授权登录接受code的参数名
|
||||
*
|
||||
* @since 1.10.0
|
||||
*/
|
||||
private String authorization_code;
|
||||
}
|
||||
|
||||
@@ -2,13 +2,12 @@ package me.zhyd.oauth.model;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
|
||||
/**
|
||||
* JustAuth统一授权响应类
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
*/
|
||||
@Getter
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package me.zhyd.oauth.model;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@@ -9,7 +8,6 @@ import lombok.Setter;
|
||||
* 授权所需的token
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
*/
|
||||
@Getter
|
||||
@@ -37,4 +35,11 @@ public class AuthToken {
|
||||
private String macAlgorithm;
|
||||
private String macKey;
|
||||
|
||||
/**
|
||||
* 企业微信附带属性
|
||||
*
|
||||
* @since 1.10.0
|
||||
*/
|
||||
private String code;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package me.zhyd.oauth.model;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.*;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
|
||||
@@ -10,15 +8,18 @@ import me.zhyd.oauth.enums.AuthUserGender;
|
||||
* 授权成功后的用户信息,根据授权平台的不同,获取的数据完整性也不同
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AuthUser {
|
||||
/**
|
||||
* 用户第三方系统的唯一id。在调用方集成改组件时,可以用uuid + source唯一确定一个用户
|
||||
*
|
||||
* @since 1.3.3
|
||||
*/
|
||||
private String uuid;
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* JustAuth核心模型类,封装了用户、token、响应和callback等实体类
|
||||
*/
|
||||
package me.zhyd.oauth.model;
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* JustAuth,如你所见,它仅仅是一个第三方授权登录的工具类库,它可以让我们脱离繁琐的第三方登录SDK,让登录变得So easy!
|
||||
* <p>
|
||||
* 史上最全的整合第三方登录的开源库。目前已支持Github、Gitee、微博、钉钉、百度、Coding、腾讯云开发者平台、OSChina、
|
||||
* 支付宝、QQ、微信、淘宝、Google、Facebook、抖音、领英、小米、微软、今日头条、Teambition、StackOverflow、Pinterest、
|
||||
* 人人、华为和企业微信等第三方平台的授权登录。 Login, so easy!
|
||||
*/
|
||||
package me.zhyd.oauth;
|
||||
@@ -7,6 +7,7 @@ import com.alipay.api.request.AlipaySystemOauthTokenRequest;
|
||||
import com.alipay.api.request.AlipayUserInfoShareRequest;
|
||||
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
|
||||
import com.alipay.api.response.AlipayUserInfoShareResponse;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
@@ -21,8 +22,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
||||
* 支付宝登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.0.1
|
||||
*/
|
||||
public class AuthAlipayRequest extends AuthDefaultRequest {
|
||||
|
||||
@@ -34,6 +34,12 @@ public class AuthAlipayRequest extends AuthDefaultRequest {
|
||||
.getAlipayPublicKey(), "RSA2");
|
||||
}
|
||||
|
||||
public AuthAlipayRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.ALIPAY, authStateCache);
|
||||
this.alipayClient = new DefaultAlipayClient(AuthSource.ALIPAY.accessToken(), config.getClientId(), config.getClientSecret(), "json", "UTF-8", config
|
||||
.getAlipayPublicKey(), "RSA2");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
|
||||
@@ -86,17 +92,19 @@ public class AuthAlipayRequest extends AuthDefaultRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回认证url,可自行跳转页面
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize() {
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("app_id", config.getClientId())
|
||||
.queryParam("scope", "auth_user")
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("state", getRealState(config.getState()))
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,16 @@ package me.zhyd.oauth.request;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.*;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.StringUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
@@ -15,8 +20,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
||||
* 百度账号登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class AuthBaiduRequest extends AuthDefaultRequest {
|
||||
|
||||
@@ -24,6 +28,10 @@ public class AuthBaiduRequest extends AuthDefaultRequest {
|
||||
super(config, AuthSource.BAIDU);
|
||||
}
|
||||
|
||||
public AuthBaiduRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.BAIDU, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
HttpResponse response = doPostAuthorizationCode(authCallback.getCode());
|
||||
@@ -79,18 +87,20 @@ public class AuthBaiduRequest extends AuthDefaultRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回认证url,可自行跳转页面
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize() {
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("display", "popup")
|
||||
.queryParam("state", getRealState(config.getState()))
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,21 +2,21 @@ package me.zhyd.oauth.request;
|
||||
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
/**
|
||||
* Cooding登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class AuthCodingRequest extends AuthDefaultRequest {
|
||||
|
||||
@@ -24,6 +24,10 @@ public class AuthCodingRequest extends AuthDefaultRequest {
|
||||
super(config, AuthSource.CODING);
|
||||
}
|
||||
|
||||
public AuthCodingRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.CODING, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
HttpResponse response = doGetAuthorizationCode(authCallback.getCode());
|
||||
@@ -71,18 +75,20 @@ public class AuthCodingRequest extends AuthDefaultRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回认证url,可自行跳转页面
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize() {
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("scope", "user")
|
||||
.queryParam("state", getRealState(config.getState()))
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package me.zhyd.oauth.request;
|
||||
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
@@ -14,8 +15,7 @@ import me.zhyd.oauth.model.AuthUser;
|
||||
* CSDN登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Deprecated
|
||||
public class AuthCsdnRequest extends AuthDefaultRequest {
|
||||
@@ -24,6 +24,10 @@ public class AuthCsdnRequest extends AuthDefaultRequest {
|
||||
super(config, AuthSource.CSDN);
|
||||
}
|
||||
|
||||
public AuthCsdnRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.CSDN, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
HttpResponse response = doPostAuthorizationCode(authCallback.getCode());
|
||||
|
||||
@@ -2,32 +2,42 @@ package me.zhyd.oauth.request;
|
||||
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhyd.oauth.cache.AuthDefaultStateCache;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.*;
|
||||
import me.zhyd.oauth.log.Log;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.AuthChecker;
|
||||
import me.zhyd.oauth.utils.StringUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
import me.zhyd.oauth.utils.UuidUtils;
|
||||
|
||||
/**
|
||||
* 默认的request处理类
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @author yangkai.shen (https://xkcoding.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class AuthDefaultRequest implements AuthRequest {
|
||||
protected AuthConfig config;
|
||||
protected AuthSource source;
|
||||
protected AuthStateCache authStateCache;
|
||||
|
||||
public AuthDefaultRequest(AuthConfig config, AuthSource source) {
|
||||
this(config, source, AuthDefaultStateCache.INSTANCE);
|
||||
}
|
||||
|
||||
public AuthDefaultRequest(AuthConfig config, AuthSource source, AuthStateCache authStateCache) {
|
||||
this.config = config;
|
||||
this.source = source;
|
||||
this.authStateCache = authStateCache;
|
||||
if (!AuthChecker.isSupportedAuth(config, source)) {
|
||||
throw new AuthException(AuthResponseStatus.PARAMETER_INCOMPLETE);
|
||||
}
|
||||
@@ -35,25 +45,53 @@ public abstract class AuthDefaultRequest implements AuthRequest {
|
||||
AuthChecker.checkConfig(config, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取access token
|
||||
*
|
||||
* @param authCallback 授权成功后的回调参数
|
||||
* @return token
|
||||
* @see AuthDefaultRequest#authorize()
|
||||
* @see AuthDefaultRequest#authorize(String)
|
||||
*/
|
||||
protected abstract AuthToken getAccessToken(AuthCallback authCallback);
|
||||
|
||||
/**
|
||||
* 使用token换取用户信息
|
||||
*
|
||||
* @param authToken token信息
|
||||
* @return 用户信息
|
||||
* @see AuthDefaultRequest#getAccessToken(AuthCallback)
|
||||
*/
|
||||
protected abstract AuthUser getUserInfo(AuthToken authToken);
|
||||
|
||||
/**
|
||||
* 统一的登录入口。当通过{@link AuthDefaultRequest#authorize(String)}授权成功后,会跳转到调用方的相关回调方法中
|
||||
* 方法的入参可以使用{@code AuthCallback},{@code AuthCallback}类中封装好了OAuth2授权回调所需要的参数
|
||||
*
|
||||
* @param authCallback 用于接收回调参数的实体
|
||||
* @return AuthResponse
|
||||
*/
|
||||
@Override
|
||||
public AuthResponse login(AuthCallback authCallback) {
|
||||
try {
|
||||
AuthChecker.checkCode(source == AuthSource.ALIPAY ? authCallback.getAuth_code() : authCallback.getCode());
|
||||
AuthChecker.checkState(authCallback.getState(), config.getState());
|
||||
AuthChecker.checkCode(source, authCallback);
|
||||
this.checkState(authCallback.getState());
|
||||
|
||||
AuthToken authToken = this.getAccessToken(authCallback);
|
||||
AuthUser user = this.getUserInfo(authToken);
|
||||
return AuthResponse.builder().code(AuthResponseStatus.SUCCESS.getCode()).data(user).build();
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to login with oauth authorization.", e);
|
||||
Log.error("Failed to login with oauth authorization.", e);
|
||||
return this.responseError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理{@link AuthDefaultRequest#login(AuthCallback)} 发生异常的情况,统一响应参数
|
||||
*
|
||||
* @param e 具体的异常
|
||||
* @return AuthResponse
|
||||
*/
|
||||
private AuthResponse responseError(Exception e) {
|
||||
int errorCode = AuthResponseStatus.FAILURE.getCode();
|
||||
if (e instanceof AuthException) {
|
||||
@@ -63,17 +101,34 @@ public abstract class AuthDefaultRequest implements AuthRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回认证url,可自行跳转页面
|
||||
* 返回授权url,可自行跳转页面
|
||||
* <p>
|
||||
* 不建议使用该方式获取授权地址,不带{@code state}的授权地址,容易受到csrf攻击。
|
||||
* 建议使用{@link AuthDefaultRequest#authorize(String)}方法生成授权地址,在回调方法中对{@code state}进行校验
|
||||
*
|
||||
* @return 返回授权地址
|
||||
* @see AuthDefaultRequest#authorize(String)
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public String authorize() {
|
||||
return this.authorize(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("state", getRealState(config.getState()))
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -130,13 +185,18 @@ public abstract class AuthDefaultRequest implements AuthRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取state,如果为空, 则默认去当前日期的时间戳
|
||||
* 获取state,如果为空, 则默认取当前日期的时间戳
|
||||
*
|
||||
* @param state 原始的state
|
||||
* @return 返回不为null的state
|
||||
*/
|
||||
protected String getRealState(String state) {
|
||||
return StringUtils.isEmpty(state) ? String.valueOf(System.currentTimeMillis()) : state;
|
||||
if (StringUtils.isEmpty(state)) {
|
||||
state = UuidUtils.getUUID();
|
||||
}
|
||||
// 缓存state
|
||||
authStateCache.cache(state, state);
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,6 +225,7 @@ public abstract class AuthDefaultRequest implements AuthRequest {
|
||||
* @param authToken token封装
|
||||
* @return HttpResponse
|
||||
*/
|
||||
@Deprecated
|
||||
protected HttpResponse doPostUserInfo(AuthToken authToken) {
|
||||
return HttpRequest.post(userInfoUrl(authToken)).execute();
|
||||
}
|
||||
@@ -185,6 +246,7 @@ public abstract class AuthDefaultRequest implements AuthRequest {
|
||||
* @param authToken token封装
|
||||
* @return HttpResponse
|
||||
*/
|
||||
@Deprecated
|
||||
protected HttpResponse doPostRevoke(AuthToken authToken) {
|
||||
return HttpRequest.post(revokeUrl(authToken)).execute();
|
||||
}
|
||||
@@ -198,4 +260,16 @@ public abstract class AuthDefaultRequest implements AuthRequest {
|
||||
protected HttpResponse doGetRevoke(AuthToken authToken) {
|
||||
return HttpRequest.get(revokeUrl(authToken)).execute();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 校验回调传回的state
|
||||
*
|
||||
* @param state {@code state}一定不为空
|
||||
*/
|
||||
protected void checkState(String state) {
|
||||
if (StringUtils.isEmpty(state) || !authStateCache.containsKey(state)) {
|
||||
throw new AuthException(AuthResponseStatus.ILLEGAL_REQUEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
@@ -18,8 +19,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
||||
* 钉钉登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class AuthDingTalkRequest extends AuthDefaultRequest {
|
||||
|
||||
@@ -27,6 +27,10 @@ public class AuthDingTalkRequest extends AuthDefaultRequest {
|
||||
super(config, AuthSource.DINGTALK);
|
||||
}
|
||||
|
||||
public AuthDingTalkRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.DINGTALK, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
return AuthToken.builder().accessCode(authCallback.getCode()).build();
|
||||
@@ -58,18 +62,20 @@ public class AuthDingTalkRequest extends AuthDefaultRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回认证url,可自行跳转页面
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize() {
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("appid", config.getClientId())
|
||||
.queryParam("scope", "snsapi_login")
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("state", getRealState(config.getState()))
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,16 @@ package me.zhyd.oauth.request;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.*;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
|
||||
@@ -15,8 +20,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
||||
* 抖音登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class AuthDouyinRequest extends AuthDefaultRequest {
|
||||
|
||||
@@ -24,6 +28,10 @@ public class AuthDouyinRequest extends AuthDefaultRequest {
|
||||
super(config, AuthSource.DOUYIN);
|
||||
}
|
||||
|
||||
public AuthDouyinRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.DOUYIN, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
return this.getToken(accessTokenUrl(authCallback.getCode()));
|
||||
@@ -89,18 +97,20 @@ public class AuthDouyinRequest extends AuthDefaultRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回认证url,可自行跳转页面
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize() {
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("client_key", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("state", getRealState(config.getState()))
|
||||
.queryParam("scope", "user_info")
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package me.zhyd.oauth.request;
|
||||
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
@@ -15,8 +16,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
||||
* Facebook登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class AuthFacebookRequest extends AuthDefaultRequest {
|
||||
|
||||
@@ -24,6 +24,10 @@ public class AuthFacebookRequest extends AuthDefaultRequest {
|
||||
super(config, AuthSource.FACEBOOK);
|
||||
}
|
||||
|
||||
public AuthFacebookRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.FACEBOOK, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
HttpResponse response = doPostAuthorizationCode(authCallback.getCode());
|
||||
|
||||
@@ -2,6 +2,7 @@ package me.zhyd.oauth.request;
|
||||
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
@@ -14,8 +15,7 @@ import me.zhyd.oauth.model.AuthUser;
|
||||
* Gitee登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class AuthGiteeRequest extends AuthDefaultRequest {
|
||||
|
||||
@@ -23,6 +23,10 @@ public class AuthGiteeRequest extends AuthDefaultRequest {
|
||||
super(config, AuthSource.GITEE);
|
||||
}
|
||||
|
||||
public AuthGiteeRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.GITEE, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
HttpResponse response = doPostAuthorizationCode(authCallback.getCode());
|
||||
|
||||
@@ -2,6 +2,7 @@ package me.zhyd.oauth.request;
|
||||
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
@@ -17,8 +18,7 @@ import java.util.Map;
|
||||
* Github登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class AuthGithubRequest extends AuthDefaultRequest {
|
||||
|
||||
@@ -26,6 +26,10 @@ public class AuthGithubRequest extends AuthDefaultRequest {
|
||||
super(config, AuthSource.GITHUB);
|
||||
}
|
||||
|
||||
public AuthGithubRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.GITHUB, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
HttpResponse response = doPostAuthorizationCode(authCallback.getCode());
|
||||
@@ -63,12 +67,4 @@ public class AuthGithubRequest extends AuthDefaultRequest {
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查响应内容是否正确
|
||||
*
|
||||
* @param object 请求响应内容
|
||||
*/
|
||||
private void checkResponse(JSONObject object) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package me.zhyd.oauth.request;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
@@ -16,8 +17,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
||||
* Google登录
|
||||
*
|
||||
* @author yangkai.shen (https://xkcoding.com)
|
||||
* @version 1.3
|
||||
* @since 1.3
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class AuthGoogleRequest extends AuthDefaultRequest {
|
||||
|
||||
@@ -25,6 +25,10 @@ public class AuthGoogleRequest extends AuthDefaultRequest {
|
||||
super(config, AuthSource.GOOGLE);
|
||||
}
|
||||
|
||||
public AuthGoogleRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.GOOGLE, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
HttpResponse response = doPostAuthorizationCode(authCallback.getCode());
|
||||
@@ -61,19 +65,20 @@ public class AuthGoogleRequest extends AuthDefaultRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回认证url,可自行跳转页面
|
||||
* https://openidconnect.googleapis.com/v1/userinfo
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize() {
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("scope", "openid%20email%20profile")
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("state", getRealState(config.getState()))
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
package me.zhyd.oauth.request;
|
||||
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
import static me.zhyd.oauth.enums.AuthResponseStatus.SUCCESS;
|
||||
|
||||
/**
|
||||
* 华为授权登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.10.0
|
||||
*/
|
||||
public class AuthHuaweiRequest extends AuthDefaultRequest {
|
||||
|
||||
public AuthHuaweiRequest(AuthConfig config) {
|
||||
super(config, AuthSource.HUAWEI);
|
||||
}
|
||||
|
||||
public AuthHuaweiRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.HUAWEI, authStateCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取access token
|
||||
*
|
||||
* @param authCallback 授权成功后的回调参数
|
||||
* @return token
|
||||
* @see AuthDefaultRequest#authorize()
|
||||
* @see AuthDefaultRequest#authorize(String)
|
||||
*/
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
HttpRequest request = HttpRequest.post(source.accessToken())
|
||||
.form("grant_type", "authorization_code")
|
||||
.form("code", authCallback.getAuthorization_code())
|
||||
.form("client_id", config.getClientId())
|
||||
.form("client_secret", config.getClientSecret())
|
||||
.form("redirect_uri", config.getRedirectUri());
|
||||
return getAuthToken(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用token换取用户信息
|
||||
*
|
||||
* @param authToken token信息
|
||||
* @return 用户信息
|
||||
* @see AuthDefaultRequest#getAccessToken(AuthCallback)
|
||||
*/
|
||||
@Override
|
||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||
HttpResponse response = HttpRequest.post(source.userInfo())
|
||||
.form("nsp_ts", System.currentTimeMillis())
|
||||
.form("access_token", authToken.getAccessToken())
|
||||
.form("nsp_fmt", "JS")
|
||||
.form("nsp_svc", "OpenUP.User.getInfo")
|
||||
.execute();
|
||||
JSONObject object = JSONObject.parseObject(response.body());
|
||||
|
||||
this.checkResponse(object);
|
||||
|
||||
AuthUserGender gender = getRealGender(object);
|
||||
|
||||
return AuthUser.builder()
|
||||
.uuid(object.getString("userID"))
|
||||
.username(object.getString("userName"))
|
||||
.nickname(object.getString("userName"))
|
||||
.gender(gender)
|
||||
.avatar(object.getString("headPictureURL"))
|
||||
.token(authToken)
|
||||
.source(source)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新access token (续期)
|
||||
*
|
||||
* @param authToken 登录成功后返回的Token信息
|
||||
* @return AuthResponse
|
||||
*/
|
||||
@Override
|
||||
public AuthResponse refresh(AuthToken authToken) {
|
||||
HttpRequest request = HttpRequest.post(source.refresh())
|
||||
.form("client_id", config.getClientId())
|
||||
.form("client_secret", config.getClientSecret())
|
||||
.form("refresh_token", authToken.getRefreshToken())
|
||||
.form("grant_type", "refresh_token");
|
||||
return AuthResponse.builder()
|
||||
.code(SUCCESS.getCode())
|
||||
.data(getAuthToken(request))
|
||||
.build();
|
||||
}
|
||||
|
||||
private AuthToken getAuthToken(HttpRequest request) {
|
||||
HttpResponse response = request.execute();
|
||||
JSONObject object = JSONObject.parseObject(response.body());
|
||||
|
||||
this.checkResponse(object);
|
||||
|
||||
return AuthToken.builder()
|
||||
.accessToken(object.getString("access_token"))
|
||||
.expireIn(object.getIntValue("expires_in"))
|
||||
.refreshToken(object.getString("refresh_token"))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("access_type", "offline")
|
||||
.queryParam("scope", "https%3A%2F%2Fwww.huawei.com%2Fauth%2Faccount%2Fbase.profile")
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回获取accessToken的url
|
||||
*
|
||||
* @param code 授权码
|
||||
* @return 返回获取accessToken的url
|
||||
*/
|
||||
@Override
|
||||
protected String accessTokenUrl(String code) {
|
||||
return UrlBuilder.fromBaseUrl(source.accessToken())
|
||||
.queryParam("grant_type", "authorization_code")
|
||||
.queryParam("code", code)
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("client_secret", config.getClientSecret())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回获取userInfo的url
|
||||
*
|
||||
* @param authToken token
|
||||
* @return 返回获取userInfo的url
|
||||
*/
|
||||
@Override
|
||||
protected String userInfoUrl(AuthToken authToken) {
|
||||
return UrlBuilder.fromBaseUrl(source.userInfo())
|
||||
.queryParam("nsp_ts", System.currentTimeMillis())
|
||||
.queryParam("access_token", authToken.getAccessToken())
|
||||
.queryParam("nsp_fmt", "JS")
|
||||
.queryParam("nsp_svc", "OpenUP.User.getInfo")
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户的实际性别。华为系统中,用户的性别:1表示女,0表示男
|
||||
*
|
||||
* @param object obj
|
||||
* @return AuthUserGender
|
||||
*/
|
||||
private AuthUserGender getRealGender(JSONObject object) {
|
||||
int genderCodeInt = object.getIntValue("gender");
|
||||
String genderCode = genderCodeInt == 1 ? "0" : (genderCodeInt == 0) ? "1" : genderCodeInt + "";
|
||||
return AuthUserGender.getRealGender(genderCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验响应结果
|
||||
*
|
||||
* @param object 接口返回的结果
|
||||
*/
|
||||
private void checkResponse(JSONObject object) {
|
||||
if (object.containsKey("NSP_STATUS")) {
|
||||
throw new AuthException(object.getString("error"));
|
||||
}
|
||||
if (object.containsKey("error")) {
|
||||
throw new AuthException(object.getString("sub_error") + ":" + object.getString("error_description"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,16 @@ import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.JSONPath;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.*;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.StringUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
@@ -18,8 +23,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
||||
* 领英登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class AuthLinkedinRequest extends AuthDefaultRequest {
|
||||
|
||||
@@ -27,6 +31,10 @@ public class AuthLinkedinRequest extends AuthDefaultRequest {
|
||||
super(config, AuthSource.LINKEDIN);
|
||||
}
|
||||
|
||||
public AuthLinkedinRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.LINKEDIN, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
return this.getToken(accessTokenUrl(authCallback.getCode()));
|
||||
@@ -113,7 +121,6 @@ public class AuthLinkedinRequest extends AuthDefaultRequest {
|
||||
* @return 用户的邮箱地址
|
||||
*/
|
||||
private String getUserEmail(String accessToken) {
|
||||
String email = null;
|
||||
HttpResponse emailResponse = HttpRequest.get("https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))")
|
||||
.header("Host", "api.linkedin.com")
|
||||
.header("Connection", "Keep-Alive")
|
||||
@@ -182,18 +189,20 @@ public class AuthLinkedinRequest extends AuthDefaultRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回认证url,可自行跳转页面
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize() {
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("state", getRealState(config.getState()))
|
||||
.queryParam("scope", "r_liteprofile%20r_emailaddress%20w_member_social")
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,12 +4,17 @@ import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.*;
|
||||
import me.zhyd.oauth.log.Log;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
@@ -18,10 +23,8 @@ import java.text.MessageFormat;
|
||||
* 小米登录
|
||||
*
|
||||
* @author yangkai.shen (https://xkcoding.com)
|
||||
* @version 1.5
|
||||
* @since 1.5
|
||||
* @since 1.5.0
|
||||
*/
|
||||
@Slf4j
|
||||
public class AuthMiRequest extends AuthDefaultRequest {
|
||||
private static final String PREFIX = "&&&START&&&";
|
||||
|
||||
@@ -29,6 +32,10 @@ public class AuthMiRequest extends AuthDefaultRequest {
|
||||
super(config, AuthSource.MI);
|
||||
}
|
||||
|
||||
public AuthMiRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.MI, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
return getToken(accessTokenUrl(authCallback.getCode()));
|
||||
@@ -88,7 +95,7 @@ public class AuthMiRequest extends AuthDefaultRequest {
|
||||
JSONObject emailPhone = userEmailPhone.getJSONObject("data");
|
||||
authUser.setEmail(emailPhone.getString("email"));
|
||||
} else {
|
||||
log.warn("小米开发平台暂时不对外开放用户手机及邮箱信息的获取");
|
||||
Log.warn("小米开发平台暂时不对外开放用户手机及邮箱信息的获取");
|
||||
}
|
||||
|
||||
return authUser;
|
||||
@@ -109,19 +116,21 @@ public class AuthMiRequest extends AuthDefaultRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回认证url,可自行跳转页面
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize() {
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("state", getRealState(config.getState()))
|
||||
.queryParam("scope", "user/profile%20user/openIdV2%20user/phoneAndEmail")
|
||||
.queryParam("skip_confirm", "false")
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,16 @@ package me.zhyd.oauth.request;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.*;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
import static me.zhyd.oauth.utils.GlobalAuthUtil.parseQueryToMap;
|
||||
@@ -16,14 +21,17 @@ import static me.zhyd.oauth.utils.GlobalAuthUtil.parseQueryToMap;
|
||||
* 微软登录
|
||||
*
|
||||
* @author yangkai.shen (https://xkcoding.com)
|
||||
* @version 1.5
|
||||
* @since 1.5
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class AuthMicrosoftRequest extends AuthDefaultRequest {
|
||||
public AuthMicrosoftRequest(AuthConfig config) {
|
||||
super(config, AuthSource.MICROSOFT);
|
||||
}
|
||||
|
||||
public AuthMicrosoftRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.MICROSOFT, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
return getToken(accessTokenUrl(authCallback.getCode()));
|
||||
@@ -102,26 +110,28 @@ public class AuthMicrosoftRequest extends AuthDefaultRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回认证url,可自行跳转页面
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize() {
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("response_mode", "query")
|
||||
.queryParam("scope", "offline_access%20user.read%20mail.read")
|
||||
.queryParam("state", getRealState(config.getState()))
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回获取accessToken的url
|
||||
*
|
||||
* @param code
|
||||
* @param code 授权code
|
||||
* @return 返回获取accessToken的url
|
||||
*/
|
||||
@Override
|
||||
|
||||
@@ -2,6 +2,7 @@ package me.zhyd.oauth.request;
|
||||
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
@@ -15,8 +16,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
||||
* oschina登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class AuthOschinaRequest extends AuthDefaultRequest {
|
||||
|
||||
@@ -24,6 +24,10 @@ public class AuthOschinaRequest extends AuthDefaultRequest {
|
||||
super(config, AuthSource.OSCHINA);
|
||||
}
|
||||
|
||||
public AuthOschinaRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.OSCHINA, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
HttpResponse response = doPostAuthorizationCode(authCallback.getCode());
|
||||
@@ -59,7 +63,7 @@ public class AuthOschinaRequest extends AuthDefaultRequest {
|
||||
/**
|
||||
* 返回获取accessToken的url
|
||||
*
|
||||
* @param code
|
||||
* @param code 授权回调时带回的授权码
|
||||
* @return 返回获取accessToken的url
|
||||
*/
|
||||
@Override
|
||||
|
||||
@@ -3,6 +3,7 @@ package me.zhyd.oauth.request;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
@@ -19,8 +20,7 @@ import static me.zhyd.oauth.config.AuthSource.PINTEREST;
|
||||
* Pinterest登录
|
||||
*
|
||||
* @author hongwei.peng (pengisgood(at)gmail(dot)com)
|
||||
* @version 1.9.0
|
||||
* @since 1.8
|
||||
* @since 1.9.0
|
||||
*/
|
||||
public class AuthPinterestRequest extends AuthDefaultRequest {
|
||||
|
||||
@@ -30,6 +30,10 @@ public class AuthPinterestRequest extends AuthDefaultRequest {
|
||||
super(config, PINTEREST);
|
||||
}
|
||||
|
||||
public AuthPinterestRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, PINTEREST, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
HttpResponse response = doPostAuthorizationCode(authCallback.getCode());
|
||||
@@ -69,14 +73,21 @@ public class AuthPinterestRequest extends AuthDefaultRequest {
|
||||
return jsonObject.getJSONObject("60x60").getString("url");
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize() {
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("state", getRealState(config.getState()))
|
||||
.queryParam("scope", "read_public")
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -86,6 +97,7 @@ public class AuthPinterestRequest extends AuthDefaultRequest {
|
||||
* @param authToken token
|
||||
* @return 返回获取userInfo的url
|
||||
*/
|
||||
@Override
|
||||
protected String userInfoUrl(AuthToken authToken) {
|
||||
return UrlBuilder.fromBaseUrl(source.userInfo())
|
||||
.queryParam("access_token", authToken.getAccessToken())
|
||||
|
||||
@@ -4,11 +4,16 @@ import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.*;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.GlobalAuthUtil;
|
||||
import me.zhyd.oauth.utils.StringUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
@@ -20,14 +25,17 @@ import java.util.Map;
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @author yangkai.shen (https://xkcoding.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class AuthQqRequest extends AuthDefaultRequest {
|
||||
public AuthQqRequest(AuthConfig config) {
|
||||
super(config, AuthSource.QQ);
|
||||
}
|
||||
|
||||
public AuthQqRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.QQ, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
HttpResponse response = doGetAuthorizationCode(authCallback.getCode());
|
||||
@@ -37,10 +45,7 @@ public class AuthQqRequest extends AuthDefaultRequest {
|
||||
@Override
|
||||
public AuthResponse refresh(AuthToken authToken) {
|
||||
HttpResponse response = HttpRequest.get(refreshTokenUrl(authToken.getRefreshToken())).execute();
|
||||
return AuthResponse.builder()
|
||||
.code(AuthResponseStatus.SUCCESS.getCode())
|
||||
.data(getAuthToken(response))
|
||||
.build();
|
||||
return AuthResponse.builder().code(AuthResponseStatus.SUCCESS.getCode()).data(getAuthToken(response)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,6 +74,13 @@ public class AuthQqRequest extends AuthDefaultRequest {
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取QQ用户的OpenId,支持自定义是否启用查询unionid的功能,如果启用查询unionid的功能,
|
||||
* 那就需要调用者先通过邮件申请unionid功能,参考链接 {@see http://wiki.connect.qq.com/unionid%E4%BB%8B%E7%BB%8D}
|
||||
*
|
||||
* @param authToken 通过{@link AuthQqRequest#getAccessToken(AuthCallback)}获取到的{@code authToken}
|
||||
* @return openId
|
||||
*/
|
||||
private String getOpenId(AuthToken authToken) {
|
||||
HttpResponse response = HttpRequest.get(UrlBuilder.fromBaseUrl("https://graph.qq.com/oauth2.0/me")
|
||||
.queryParam("access_token", authToken.getAccessToken())
|
||||
|
||||
@@ -4,23 +4,26 @@ import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.*;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static me.zhyd.oauth.config.AuthSource.RENREN;
|
||||
import static me.zhyd.oauth.model.AuthResponseStatus.SUCCESS;
|
||||
import static me.zhyd.oauth.enums.AuthResponseStatus.SUCCESS;
|
||||
|
||||
/**
|
||||
* 人人登录
|
||||
*
|
||||
* @author hongwei.peng (pengisgood(at)gmail(dot)com)
|
||||
* @version 1.9.0
|
||||
* @since 1.8
|
||||
* @since 1.9.0
|
||||
*/
|
||||
public class AuthRenrenRequest extends AuthDefaultRequest {
|
||||
|
||||
@@ -28,6 +31,10 @@ public class AuthRenrenRequest extends AuthDefaultRequest {
|
||||
super(config, RENREN);
|
||||
}
|
||||
|
||||
public AuthRenrenRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, RENREN, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
return this.getToken(accessTokenUrl(authCallback.getCode()));
|
||||
|
||||
@@ -1,27 +1,48 @@
|
||||
package me.zhyd.oauth.request;
|
||||
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthResponseStatus;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
|
||||
/**
|
||||
* JustAuth {@code Request}公共接口,所有平台的{@code Request}都需要实现该接口
|
||||
* <p>
|
||||
* {@link AuthRequest#authorize()}
|
||||
* {@link AuthRequest#authorize(String)}
|
||||
* {@link AuthRequest#login(AuthCallback)}
|
||||
* {@link AuthRequest#revoke(AuthToken)}
|
||||
* {@link AuthRequest#refresh(AuthToken)}
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
*/
|
||||
public interface AuthRequest {
|
||||
|
||||
/**
|
||||
* 返回认证url,可自行跳转页面
|
||||
* 返回授权url,可自行跳转页面
|
||||
* <p>
|
||||
* 不建议使用该方式获取授权地址,不带{@code state}的授权地址,容易受到csrf攻击。
|
||||
* 建议使用{@link AuthDefaultRequest#authorize(String)}方法生成授权地址,在回调方法中对{@code state}进行校验
|
||||
*
|
||||
* @return 返回授权地址
|
||||
*/
|
||||
@Deprecated
|
||||
default String authorize() {
|
||||
throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
*/
|
||||
default String authorize(String state) {
|
||||
throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* 第三方登录
|
||||
*
|
||||
|
||||
@@ -3,6 +3,7 @@ package me.zhyd.oauth.request;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
@@ -18,8 +19,7 @@ import static me.zhyd.oauth.utils.GlobalAuthUtil.parseQueryToMap;
|
||||
* Stack Overflow登录
|
||||
*
|
||||
* @author hongwei.peng (pengisgood(at)gmail(dot)com)
|
||||
* @version 1.9.0
|
||||
* @since 1.8
|
||||
* @since 1.9.0
|
||||
*/
|
||||
public class AuthStackOverflowRequest extends AuthDefaultRequest {
|
||||
|
||||
@@ -27,6 +27,10 @@ public class AuthStackOverflowRequest extends AuthDefaultRequest {
|
||||
super(config, STACK_OVERFLOW);
|
||||
}
|
||||
|
||||
public AuthStackOverflowRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, STACK_OVERFLOW, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
String accessTokenUrl = accessTokenUrl(authCallback.getCode());
|
||||
@@ -67,14 +71,21 @@ public class AuthStackOverflowRequest extends AuthDefaultRequest {
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize() {
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("state", getRealState(config.getState()))
|
||||
.queryParam("scope", "read_inbox")
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,14 @@ package me.zhyd.oauth.request;
|
||||
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.utils.GlobalAuthUtil;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
@@ -16,8 +17,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
||||
* 淘宝登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class AuthTaobaoRequest extends AuthDefaultRequest {
|
||||
|
||||
@@ -25,6 +25,10 @@ public class AuthTaobaoRequest extends AuthDefaultRequest {
|
||||
super(config, AuthSource.TAOBAO);
|
||||
}
|
||||
|
||||
public AuthTaobaoRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.TAOBAO, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
return AuthToken.builder().accessCode(authCallback.getCode()).build();
|
||||
@@ -55,18 +59,20 @@ public class AuthTaobaoRequest extends AuthDefaultRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回认证url,可自行跳转页面
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize() {
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("state", getRealState(config.getState()))
|
||||
.queryParam("view", "web")
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,18 +3,22 @@ package me.zhyd.oauth.request;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.*;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
|
||||
/**
|
||||
* Teambition授权登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.9.0
|
||||
*/
|
||||
public class AuthTeambitionRequest extends AuthDefaultRequest {
|
||||
|
||||
@@ -22,6 +26,10 @@ public class AuthTeambitionRequest extends AuthDefaultRequest {
|
||||
super(config, AuthSource.TEAMBITION);
|
||||
}
|
||||
|
||||
public AuthTeambitionRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.TEAMBITION, authStateCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param authCallback 回调返回的参数
|
||||
* @return 所有信息
|
||||
|
||||
@@ -2,6 +2,7 @@ package me.zhyd.oauth.request;
|
||||
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
@@ -15,8 +16,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
||||
* 腾讯云登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class AuthTencentCloudRequest extends AuthDefaultRequest {
|
||||
|
||||
@@ -24,6 +24,10 @@ public class AuthTencentCloudRequest extends AuthDefaultRequest {
|
||||
super(config, AuthSource.TENCENT_CLOUD);
|
||||
}
|
||||
|
||||
public AuthTencentCloudRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.TENCENT_CLOUD, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
HttpResponse response = doGetAuthorizationCode(authCallback.getCode());
|
||||
@@ -71,18 +75,20 @@ public class AuthTencentCloudRequest extends AuthDefaultRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回认证url,可自行跳转页面
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize() {
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("scope", "user")
|
||||
.queryParam("state", getRealState(config.getState()))
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package me.zhyd.oauth.request;
|
||||
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthToutiaoErrorCode;
|
||||
@@ -16,8 +17,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
||||
* 今日头条登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.5
|
||||
* @since 1.5
|
||||
* @since 1.6.0-beta
|
||||
*/
|
||||
public class AuthToutiaoRequest extends AuthDefaultRequest {
|
||||
|
||||
@@ -25,6 +25,10 @@ public class AuthToutiaoRequest extends AuthDefaultRequest {
|
||||
super(config, AuthSource.TOUTIAO);
|
||||
}
|
||||
|
||||
public AuthToutiaoRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.TOUTIAO, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
HttpResponse response = doGetAuthorizationCode(authCallback.getCode());
|
||||
@@ -65,19 +69,21 @@ public class AuthToutiaoRequest extends AuthDefaultRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回认证url,可自行跳转页面
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize() {
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("client_key", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("state", getRealState(config.getState()))
|
||||
.queryParam("auth_only", 1)
|
||||
.queryParam("display", 0)
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -118,8 +124,7 @@ public class AuthToutiaoRequest extends AuthDefaultRequest {
|
||||
*/
|
||||
private void checkResponse(JSONObject object) {
|
||||
if (object.containsKey("error_code")) {
|
||||
throw new AuthException(AuthToutiaoErrorCode.getErrorCode(object.getIntValue("error_code"))
|
||||
.getDesc());
|
||||
throw new AuthException(AuthToutiaoErrorCode.getErrorCode(object.getIntValue("error_code")).getDesc());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
package me.zhyd.oauth.request;
|
||||
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 企业微信登录
|
||||
* </p>
|
||||
*
|
||||
* @author yangkai.shen (https://xkcoding.com)
|
||||
* @since 1.10.0
|
||||
*/
|
||||
public class AuthWeChatEnterpriseRequest extends AuthDefaultRequest {
|
||||
public AuthWeChatEnterpriseRequest(AuthConfig config) {
|
||||
super(config, AuthSource.WECHAT_ENTERPRISE);
|
||||
}
|
||||
|
||||
public AuthWeChatEnterpriseRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.WECHAT_ENTERPRISE, authStateCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信的特殊性,此时返回的信息同时包含 openid 和 access_token
|
||||
*
|
||||
* @param authCallback 回调返回的参数
|
||||
* @return 所有信息
|
||||
*/
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
HttpResponse response = doGetAuthorizationCode(accessTokenUrl(authCallback.getCode()));
|
||||
|
||||
JSONObject object = this.checkResponse(response);
|
||||
|
||||
return AuthToken.builder()
|
||||
.accessToken(object.getString("access_token"))
|
||||
.expireIn(object.getIntValue("expires_in"))
|
||||
.code(authCallback.getCode())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||
HttpResponse response = doGetUserInfo(authToken);
|
||||
JSONObject object = this.checkResponse(response);
|
||||
|
||||
// 返回 OpenId 或其他,均代表非当前企业用户,不支持
|
||||
if (!object.containsKey("UserId")) {
|
||||
throw new AuthException(AuthResponseStatus.UNIDENTIFIED_PLATFORM);
|
||||
}
|
||||
String userId = object.getString("UserId");
|
||||
HttpResponse userDetailResponse = getUserDetail(authToken.getAccessToken(), userId);
|
||||
JSONObject userDetail = this.checkResponse(userDetailResponse);
|
||||
|
||||
String gender = getRealGender(userDetail);
|
||||
|
||||
return AuthUser.builder()
|
||||
.username(userDetail.getString("name"))
|
||||
.nickname(userDetail.getString("alias"))
|
||||
.avatar(userDetail.getString("avatar"))
|
||||
.location(userDetail.getString("address"))
|
||||
.email(userDetail.getString("email"))
|
||||
.uuid(userId)
|
||||
.gender(AuthUserGender.getRealGender(gender))
|
||||
.token(authToken)
|
||||
.source(source)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验请求结果
|
||||
*
|
||||
* @param response 请求结果
|
||||
* @return 如果请求结果正常,则返回JSONObject
|
||||
*/
|
||||
private JSONObject checkResponse(HttpResponse response) {
|
||||
JSONObject object = JSONObject.parseObject(response.body());
|
||||
|
||||
if (object.containsKey("errcode") && object.getIntValue("errcode") != 0) {
|
||||
throw new AuthException(object.getIntValue("errcode"), object.getString("errmsg"));
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户的实际性别,0表示未定义,1表示男性,2表示女性
|
||||
*
|
||||
* @param userDetail 用户详情
|
||||
* @return 用户性别
|
||||
*/
|
||||
private String getRealGender(JSONObject userDetail) {
|
||||
int gender = userDetail.getIntValue("gender");
|
||||
if (AuthUserGender.MALE.getCode() == gender) {
|
||||
return "1";
|
||||
}
|
||||
return 2 == gender ? "0" : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("appid", config.getClientId())
|
||||
.queryParam("agentid", config.getAgentId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回获取accessToken的url
|
||||
*
|
||||
* @param code 授权码
|
||||
* @return 返回获取accessToken的url
|
||||
*/
|
||||
@Override
|
||||
protected String accessTokenUrl(String code) {
|
||||
return UrlBuilder.fromBaseUrl(source.accessToken())
|
||||
.queryParam("corpid", config.getClientId())
|
||||
.queryParam("corpsecret", config.getClientSecret())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回获取userInfo的url
|
||||
*
|
||||
* @param authToken 用户授权后的token
|
||||
* @return 返回获取userInfo的url
|
||||
*/
|
||||
@Override
|
||||
protected String userInfoUrl(AuthToken authToken) {
|
||||
return UrlBuilder.fromBaseUrl(source.userInfo())
|
||||
.queryParam("access_token", authToken.getAccessToken())
|
||||
.queryParam("code", authToken.getCode())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户详情
|
||||
*
|
||||
* @param accessToken accessToken
|
||||
* @param userId 企业内用户id
|
||||
* @return 用户详情
|
||||
*/
|
||||
private HttpResponse getUserDetail(String accessToken, String userId) {
|
||||
String userDetailUrl = UrlBuilder.fromBaseUrl("https://qyapi.weixin.qq.com/cgi-bin/user/get")
|
||||
.queryParam("access_token", accessToken)
|
||||
.queryParam("userid", userId)
|
||||
.build();
|
||||
return HttpRequest.get(userDetailUrl).execute();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,25 +3,33 @@ package me.zhyd.oauth.request;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.*;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
/**
|
||||
* 微信登录
|
||||
*
|
||||
* @author yangkai.shen (https://xkcoding.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public class AuthWeChatRequest extends AuthDefaultRequest {
|
||||
public AuthWeChatRequest(AuthConfig config) {
|
||||
super(config, AuthSource.WECHAT);
|
||||
}
|
||||
|
||||
public AuthWeChatRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.WECHAT, authStateCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信的特殊性,此时返回的信息同时包含 openid 和 access_token
|
||||
*
|
||||
@@ -100,18 +108,20 @@ public class AuthWeChatRequest extends AuthDefaultRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回认证url,可自行跳转页面
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize() {
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("appid", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("scope", "snsapi_login")
|
||||
.queryParam("state", getRealState(config.getState()).concat("#wechat_redirect"))
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package me.zhyd.oauth.request;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
@@ -19,8 +20,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
||||
* 微博登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class AuthWeiboRequest extends AuthDefaultRequest {
|
||||
|
||||
@@ -28,6 +28,10 @@ public class AuthWeiboRequest extends AuthDefaultRequest {
|
||||
super(config, AuthSource.WEIBO);
|
||||
}
|
||||
|
||||
public AuthWeiboRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthSource.WEIBO, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
HttpResponse response = doPostAuthorizationCode(authCallback.getCode());
|
||||
@@ -51,7 +55,7 @@ public class AuthWeiboRequest extends AuthDefaultRequest {
|
||||
String oauthParam = String.format("uid=%s&access_token=%s", uid, accessToken);
|
||||
HttpResponse response = HttpRequest.get(userInfoUrl(authToken))
|
||||
.header("Authorization", "OAuth2 " + oauthParam)
|
||||
.header("API-RemoteIP", IpUtils.getIp())
|
||||
.header("API-RemoteIP", IpUtils.getLocalIp())
|
||||
.execute();
|
||||
String userInfo = response.body();
|
||||
JSONObject object = JSONObject.parseObject(userInfo);
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* JustAuth核心组件,所有授权登录都是基于{@code request}实现
|
||||
*/
|
||||
package me.zhyd.oauth.request;
|
||||
@@ -2,15 +2,15 @@ package me.zhyd.oauth.utils;
|
||||
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.AuthResponseStatus;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
|
||||
/**
|
||||
* 授权配置类的校验器
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.6.1-beta
|
||||
*/
|
||||
public class AuthChecker {
|
||||
|
||||
@@ -20,6 +20,7 @@ public class AuthChecker {
|
||||
* @param config config
|
||||
* @param source source
|
||||
* @return true or false
|
||||
* @since 1.6.1-beta
|
||||
*/
|
||||
public static boolean isSupportedAuth(AuthConfig config, AuthSource source) {
|
||||
boolean isSupported = StringUtils.isNotEmpty(config.getClientId()) && StringUtils.isNotEmpty(config.getClientSecret()) && StringUtils.isNotEmpty(config.getRedirectUri());
|
||||
@@ -29,6 +30,9 @@ public class AuthChecker {
|
||||
if (isSupported && AuthSource.STACK_OVERFLOW == source) {
|
||||
isSupported = StringUtils.isNotEmpty(config.getStackOverflowKey());
|
||||
}
|
||||
if (isSupported && AuthSource.WECHAT_ENTERPRISE == source){
|
||||
isSupported = StringUtils.isNotEmpty(config.getAgentId());
|
||||
}
|
||||
return isSupported;
|
||||
}
|
||||
|
||||
@@ -37,6 +41,7 @@ public class AuthChecker {
|
||||
*
|
||||
* @param config config
|
||||
* @param source source
|
||||
* @since 1.6.1-beta
|
||||
*/
|
||||
public static void checkConfig(AuthConfig config, AuthSource source) {
|
||||
String redirectUri = config.getRedirectUri();
|
||||
@@ -55,33 +60,22 @@ public class AuthChecker {
|
||||
|
||||
/**
|
||||
* 校验回调传回的code
|
||||
* <p>
|
||||
* {@code v1.10.0}版本中改为传入{@code source}和{@code callback},对于不同平台使用不同参数接受code的情况统一做处理
|
||||
*
|
||||
* @param code 回调时传回的code
|
||||
* @param source 当前授权平台
|
||||
* @param callback 从第三方授权回调回来时传入的参数集合
|
||||
* @since 1.8.0
|
||||
*/
|
||||
public static void checkCode(String code) {
|
||||
public static void checkCode(AuthSource source, AuthCallback callback) {
|
||||
String code = callback.getCode();
|
||||
if (source == AuthSource.ALIPAY) {
|
||||
code = callback.getAuth_code();
|
||||
} else if (source == AuthSource.HUAWEI) {
|
||||
code = callback.getAuthorization_code();
|
||||
}
|
||||
if (StringUtils.isEmpty(code)) {
|
||||
throw new AuthException(AuthResponseStatus.ILLEGAL_CODE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验state的合法性防止被CSRF
|
||||
*
|
||||
* @param newState 新的state,一般为回调时传回的state(可能被篡改)
|
||||
* @param originalState 原始的state,发起授权时向第三方平台传递的state
|
||||
*/
|
||||
public static void checkState(String newState, String originalState) {
|
||||
// 如果原始state为空,表示当前平台未使用state
|
||||
if (StringUtils.isEmpty(originalState)) {
|
||||
return;
|
||||
}
|
||||
// 如果授权之前使用了state,但是回调时未返回state,则表示当前请求为非法的请求,可能正在被CSRF攻击
|
||||
if (StringUtils.isEmpty(newState)) {
|
||||
throw new AuthException(AuthResponseStatus.ILLEGAL_REQUEST);
|
||||
}
|
||||
// 如果授权前后的state不一致,则表示当前请求为非法的请求,新的state可能为伪造
|
||||
if (!newState.equals(originalState)) {
|
||||
throw new AuthException(AuthResponseStatus.ILLEGAL_REQUEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,185 +0,0 @@
|
||||
package me.zhyd.oauth.utils;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.AuthResponseStatus;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* state工具,负责创建、获取和删除state
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
*/
|
||||
@Slf4j
|
||||
public class AuthState {
|
||||
|
||||
/**
|
||||
* 空字符串
|
||||
*/
|
||||
private static final String EMPTY_STR = "";
|
||||
|
||||
/**
|
||||
* state存储器
|
||||
*/
|
||||
private static ConcurrentHashMap<String, String> stateBucket = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 生成随机的state
|
||||
*
|
||||
* @param source oauth平台
|
||||
* @return state
|
||||
*/
|
||||
public static String create(AuthSource source) {
|
||||
return create(source.name());
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成随机的state
|
||||
*
|
||||
* @param source oauth平台
|
||||
* @return state
|
||||
*/
|
||||
public static String create(String source) {
|
||||
return create(source, RandomUtil.randomString(4));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建state
|
||||
*
|
||||
* @param source oauth平台
|
||||
* @param body 希望加密到state的消息体
|
||||
* @return state
|
||||
*/
|
||||
public static String create(String source, Object body) {
|
||||
return create(source, JSON.toJSONString(body));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建state
|
||||
*
|
||||
* @param source oauth平台
|
||||
* @param body 希望加密到state的消息体
|
||||
* @return state
|
||||
*/
|
||||
public static String create(String source, String body) {
|
||||
String currentIp = getCurrentIp();
|
||||
String simpleKey = ((source + currentIp));
|
||||
String key = Base64.encode(simpleKey.getBytes(Charset.forName("UTF-8")));
|
||||
log.debug("Create the state: ip={}, platform={}, simpleKey={}, key={}, body={}", currentIp, source, simpleKey, key, body);
|
||||
|
||||
if (stateBucket.containsKey(key)) {
|
||||
log.debug("Get from bucket: {}", stateBucket.get(key));
|
||||
return stateBucket.get(key);
|
||||
}
|
||||
|
||||
String simpleState = source + "_" + currentIp + "_" + body;
|
||||
String state = Base64.encode(simpleState.getBytes(Charset.forName("UTF-8")));
|
||||
log.debug("Create a new state: {}", state, simpleState);
|
||||
stateBucket.put(key, state);
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取state
|
||||
*
|
||||
* @param source oauth平台
|
||||
* @return state
|
||||
*/
|
||||
public static String get(String source) {
|
||||
String currentIp = getCurrentIp();
|
||||
String simpleKey = ((source + currentIp));
|
||||
String key = Base64.encode(simpleKey.getBytes(Charset.forName("UTF-8")));
|
||||
log.debug("Get state by the key[{}], current ip[{}]", key, currentIp);
|
||||
return stateBucket.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取state中保存的body内容
|
||||
*
|
||||
* @param source oauth平台
|
||||
* @param state 加密后的state
|
||||
* @param clazz body的实际类型
|
||||
* @param <T> 需要转换的具体的class类型
|
||||
* @return state
|
||||
*/
|
||||
public static <T> T getBody(String source, String state, Class<T> clazz) {
|
||||
if (StringUtils.isEmpty(state) || null == clazz) {
|
||||
return null;
|
||||
}
|
||||
log.debug("Get body from the state[{}] of the {} and convert it to {}", state, source, clazz.toString());
|
||||
String currentIp = getCurrentIp();
|
||||
String decodedState = Base64.decodeStr(state);
|
||||
log.debug("The decoded state is [{}]", decodedState);
|
||||
if (!decodedState.startsWith(source)) {
|
||||
return null;
|
||||
}
|
||||
String noneSourceState = decodedState.substring(source.length() + 1);
|
||||
if (!noneSourceState.startsWith(currentIp)) {
|
||||
// ip不相同,可能为非法的请求
|
||||
throw new AuthException(AuthResponseStatus.ILLEGAL_REQUEST);
|
||||
}
|
||||
String body = noneSourceState.substring(currentIp.length() + 1);
|
||||
log.debug("body is [{}]", body);
|
||||
if (clazz == String.class) {
|
||||
return (T) body;
|
||||
}
|
||||
if (clazz == Integer.class) {
|
||||
return (T) Integer.valueOf(Integer.parseInt(body));
|
||||
}
|
||||
if (clazz == Long.class) {
|
||||
return (T) Long.valueOf(Long.parseLong(body));
|
||||
}
|
||||
if (clazz == Short.class) {
|
||||
return (T) Short.valueOf(Short.parseShort(body));
|
||||
}
|
||||
if (clazz == Double.class) {
|
||||
return (T) Double.valueOf(Double.parseDouble(body));
|
||||
}
|
||||
if (clazz == Float.class) {
|
||||
return (T) Float.valueOf(Float.parseFloat(body));
|
||||
}
|
||||
if (clazz == Boolean.class) {
|
||||
return (T) Boolean.valueOf(Boolean.parseBoolean(body));
|
||||
}
|
||||
if (clazz == Byte.class) {
|
||||
return (T) Byte.valueOf(Byte.parseByte(body));
|
||||
}
|
||||
return JSON.parseObject(body, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录成功后,清除state
|
||||
*
|
||||
* @param source oauth平台
|
||||
*/
|
||||
public static void delete(String source) {
|
||||
String currentIp = getCurrentIp();
|
||||
|
||||
String simpleKey = ((source + currentIp));
|
||||
String key = Base64.encode(simpleKey.getBytes(Charset.forName("UTF-8")));
|
||||
log.debug("Delete used state[{}] by the key[{}], current ip[{}]", stateBucket.get(key), key, currentIp);
|
||||
stateBucket.remove(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录成功后,清除state
|
||||
*
|
||||
* @param source oauth平台
|
||||
*/
|
||||
public static void delete(AuthSource source) {
|
||||
delete(source.name());
|
||||
}
|
||||
|
||||
private static String getCurrentIp() {
|
||||
String currentIp = IpUtils.getIp();
|
||||
return StringUtils.isEmpty(currentIp) ? EMPTY_STR : currentIp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package me.zhyd.oauth.utils;
|
||||
|
||||
/**
|
||||
* AuthState工具类,默认只提供一个创建随机uuid的方法
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.9.3
|
||||
*/
|
||||
public class AuthStateUtils {
|
||||
|
||||
/**
|
||||
* 生成随机state,采用https://github.com/lets-mica/mica的UUID工具
|
||||
*
|
||||
* @return 随机的state字符串
|
||||
*/
|
||||
public static String createState() {
|
||||
return UuidUtils.getUUID();
|
||||
}
|
||||
}
|
||||
@@ -21,8 +21,7 @@ import java.util.*;
|
||||
* 全局的工具类
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class GlobalAuthUtil {
|
||||
private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
|
||||
|
||||
@@ -7,8 +7,7 @@ import java.net.UnknownHostException;
|
||||
* 获取IP的工具类
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class IpUtils {
|
||||
|
||||
@@ -17,7 +16,7 @@ public class IpUtils {
|
||||
*
|
||||
* @return ip
|
||||
*/
|
||||
public static String getIp() {
|
||||
public static String getLocalIp() {
|
||||
try {
|
||||
return InetAddress.getLocalHost().getHostAddress();
|
||||
} catch (UnknownHostException e) {
|
||||
@@ -25,4 +24,4 @@ public class IpUtils {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package me.zhyd.oauth.utils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class StringUtils {
|
||||
|
||||
@@ -14,4 +16,24 @@ public class StringUtils {
|
||||
public static boolean isNotEmpty(String str) {
|
||||
return !isEmpty(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果给定字符串{@code str}中不包含{@code appendStr},则在{@code str}后追加{@code appendStr};
|
||||
* 如果已包含{@code appendStr},则在{@code str}后追加{@code otherwise}
|
||||
*
|
||||
* @param str 给定的字符串
|
||||
* @param appendStr 需要追加的内容
|
||||
* @param otherwise 当{@code appendStr}不满足时追加到{@code str}后的内容
|
||||
* @return 追加后的字符串
|
||||
*/
|
||||
public static String appendIfNotContain(String str, String appendStr, String otherwise) {
|
||||
if (isEmpty(str) || isEmpty(appendStr)) {
|
||||
return str;
|
||||
}
|
||||
if (str.contains(appendStr)) {
|
||||
return str.concat(otherwise);
|
||||
}
|
||||
return str.concat(appendStr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,8 +14,7 @@ import java.util.Map;
|
||||
* </p>
|
||||
*
|
||||
* @author yangkai.shen (https://xkcoding.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
* @since 1.9.0
|
||||
*/
|
||||
@Setter
|
||||
public class UrlBuilder {
|
||||
@@ -72,7 +71,7 @@ public class UrlBuilder {
|
||||
if (MapUtil.isEmpty(this.params)) {
|
||||
return this.baseUrl;
|
||||
}
|
||||
String baseUrl = StrUtil.addSuffixIfNot(this.baseUrl, "?");
|
||||
String baseUrl = StringUtils.appendIfNotContain(this.baseUrl, "?", "&");
|
||||
String paramString = GlobalAuthUtil.parseMapToString(this.params, encode);
|
||||
return baseUrl + paramString;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package me.zhyd.oauth.utils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* 高性能的创建UUID的工具类,https://github.com/lets-mica/mica
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.9.3
|
||||
*/
|
||||
public class UuidUtils {
|
||||
|
||||
/**
|
||||
* All possible chars for representing a number as a String
|
||||
* copy from mica:https://github.com/lets-mica/mica/blob/master/mica-core/src/main/java/net/dreamlu/mica/core/utils/NumberUtil.java#L113
|
||||
*/
|
||||
private final static byte[] DIGITS = {
|
||||
'0', '1', '2', '3', '4', '5',
|
||||
'6', '7', '8', '9', 'a', 'b',
|
||||
'c', 'd', 'e', 'f', 'g', 'h',
|
||||
'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't',
|
||||
'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'A', 'B', 'C', 'D', 'E', 'F',
|
||||
'G', 'H', 'I', 'J', 'K', 'L',
|
||||
'M', 'N', 'O', 'P', 'Q', 'R',
|
||||
'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z'
|
||||
};
|
||||
|
||||
/**
|
||||
* 生成uuid,采用 jdk 9 的形式,优化性能
|
||||
* copy from mica:https://github.com/lets-mica/mica/blob/master/mica-core/src/main/java/net/dreamlu/mica/core/utils/StringUtil.java#L335
|
||||
* <p>
|
||||
* 关于mica uuid生成方式的压测结果,可以参考:https://github.com/lets-mica/mica-jmh/wiki/uuid
|
||||
*
|
||||
* @return UUID
|
||||
*/
|
||||
public static String getUUID() {
|
||||
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||
long lsb = random.nextLong();
|
||||
long msb = random.nextLong();
|
||||
byte[] buf = new byte[32];
|
||||
formatUnsignedLong(lsb, buf, 20, 12);
|
||||
formatUnsignedLong(lsb >>> 48, buf, 16, 4);
|
||||
formatUnsignedLong(msb, buf, 12, 4);
|
||||
formatUnsignedLong(msb >>> 16, buf, 8, 4);
|
||||
formatUnsignedLong(msb >>> 32, buf, 0, 8);
|
||||
return new String(buf, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* copy from mica:https://github.com/lets-mica/mica/blob/master/mica-core/src/main/java/net/dreamlu/mica/core/utils/StringUtil.java#L348
|
||||
*/
|
||||
private static void formatUnsignedLong(long val, byte[] buf, int offset, int len) {
|
||||
int charPos = offset + len;
|
||||
int radix = 1 << 4;
|
||||
int mask = radix - 1;
|
||||
do {
|
||||
buf[--charPos] = DIGITS[((int) val) & mask];
|
||||
val >>>= 4;
|
||||
} while (charPos > offset);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 提供一些简单的工具和校验等
|
||||
*/
|
||||
package me.zhyd.oauth.utils;
|
||||
@@ -8,274 +8,302 @@ import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.8
|
||||
*/
|
||||
public class AuthRequestTest {
|
||||
|
||||
@Test
|
||||
public void giteeTest() {
|
||||
AuthRequest authRequest = new AuthGiteeRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.state("state")
|
||||
.build());
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("http://redirectUri")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
authRequest.authorize();
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
authRequest.login(new AuthCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void githubTest() {
|
||||
AuthRequest authRequest = new AuthGithubRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.state("state")
|
||||
.build());
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("http://redirectUri")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
authRequest.authorize();
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
authRequest.login(new AuthCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void weiboTest() {
|
||||
AuthRequest authRequest = new AuthWeiboRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.build());
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("http://redirectUri")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
authRequest.authorize();
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
authRequest.login(new AuthCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dingdingTest() {
|
||||
AuthRequest authRequest = new AuthDingTalkRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.state("state")
|
||||
.build());
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("http://redirectUri")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
String url = authRequest.authorize();
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
authRequest.login(new AuthCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void baiduTest() {
|
||||
AuthRequest authRequest = new AuthBaiduRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.state("state")
|
||||
.build());
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("http://redirectUri")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
String url = authRequest.authorize();
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
authRequest.login(new AuthCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void codingTest() {
|
||||
AuthRequest authRequest = new AuthCodingRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.state("state")
|
||||
.build());
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("http://redirectUri")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
String url = authRequest.authorize();
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
authRequest.login(new AuthCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tencentCloudTest() {
|
||||
AuthRequest authRequest = new AuthTencentCloudRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.state("state")
|
||||
.build());
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("http://redirectUri")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
String url = authRequest.authorize();
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
authRequest.login(new AuthCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void oschinaTest() {
|
||||
AuthRequest authRequest = new AuthOschinaRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.state("state")
|
||||
.build());
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("http://redirectUri")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
String url = authRequest.authorize();
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
authRequest.login(new AuthCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void alipayTest() {
|
||||
AuthRequest authRequest = new AuthAlipayRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.alipayPublicKey("publicKey")
|
||||
.state("state")
|
||||
.build());
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("http://redirectUri")
|
||||
.alipayPublicKey("publicKey")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
String url = authRequest.authorize();
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
AuthResponse login = authRequest.login(new AuthCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void qqTest() {
|
||||
AuthRequest authRequest = new AuthQqRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.state("state")
|
||||
.build());
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("http://redirectUri")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
String url = authRequest.authorize();
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
AuthResponse login = authRequest.login(new AuthCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wechatTest() {
|
||||
AuthRequest authRequest = new AuthWeChatRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.state("state")
|
||||
.build());
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("http://redirectUri")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
String url = authRequest.authorize();
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
AuthResponse login = authRequest.login(new AuthCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void taobaoTest() {
|
||||
AuthRequest authRequest = new AuthTaobaoRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.state("state")
|
||||
.build());
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("http://redirectUri")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
String url = authRequest.authorize();
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
AuthResponse login = authRequest.login(new AuthCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void googleTest() {
|
||||
AuthRequest authRequest = new AuthGoogleRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.state("state")
|
||||
.build());
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("http://redirectUri")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
String url = authRequest.authorize();
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
AuthResponse login = authRequest.login(new AuthCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void facebookTest() {
|
||||
AuthRequest authRequest = new AuthFacebookRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.state("state")
|
||||
.build());
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("https://redirectUri")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
String url = authRequest.authorize();
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
AuthResponse login = authRequest.login(new AuthCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void douyinTest() {
|
||||
AuthRequest authRequest = new AuthDouyinRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.state("state")
|
||||
.build());
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("http://redirectUri")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
String url = authRequest.authorize();
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
AuthResponse login = authRequest.login(new AuthCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void linkedinTest() {
|
||||
AuthRequest authRequest = new AuthLinkedinRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.state("state")
|
||||
.build());
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("http://redirectUri")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
String url = authRequest.authorize();
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
AuthResponse login = authRequest.login(new AuthCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void microsoftTest() {
|
||||
AuthRequest authRequest = new AuthMicrosoftRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.state("state")
|
||||
.build());
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("http://redirectUri")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
String url = authRequest.authorize();
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
AuthResponse login = authRequest.login(new AuthCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void miTest() {
|
||||
AuthRequest authRequest = new AuthMiRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.state("state")
|
||||
.build());
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("http://redirectUri")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
String url = authRequest.authorize();
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
AuthResponse login = authRequest.login(new AuthCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toutiaoTest() {
|
||||
AuthRequest authRequest = new AuthToutiaoRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.state("state")
|
||||
.build());
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("http://redirectUri")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
String url = authRequest.authorize();
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
AuthResponse login = authRequest.login(new AuthCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void huaweiTest() {
|
||||
AuthRequest authRequest = new AuthHuaweiRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("http://redirectUri")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
AuthResponse login = authRequest.login(new AuthCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void weChatEnterpriseTest() {
|
||||
AuthRequest authRequest = new AuthWeChatEnterpriseRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("http://redirectUri")
|
||||
.agentId("agentId")
|
||||
.build());
|
||||
// 返回授权页面,可自行跳转
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
AuthResponse login = authRequest.login(new AuthCallback());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package me.zhyd.oauth.cache;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class AuthStateCacheTest {
|
||||
|
||||
@Test
|
||||
public void cache1() throws InterruptedException {
|
||||
AuthDefaultStateCache.INSTANCE.cache("key", "value");
|
||||
Assert.assertEquals(AuthDefaultStateCache.INSTANCE.get("key"), "value");
|
||||
|
||||
TimeUnit.MILLISECONDS.sleep(4);
|
||||
Assert.assertEquals(AuthDefaultStateCache.INSTANCE.get("key"), "value");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cache2() throws InterruptedException {
|
||||
AuthDefaultStateCache.INSTANCE.cache("key", "value", 10);
|
||||
Assert.assertEquals(AuthDefaultStateCache.INSTANCE.get("key"), "value");
|
||||
|
||||
// 没过期
|
||||
TimeUnit.MILLISECONDS.sleep(5);
|
||||
Assert.assertEquals(AuthDefaultStateCache.INSTANCE.get("key"), "value");
|
||||
|
||||
// 过期
|
||||
TimeUnit.MILLISECONDS.sleep(6);
|
||||
Assert.assertNull(AuthDefaultStateCache.INSTANCE.get("key"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package me.zhyd.oauth.log;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @date 2019/8/2 19:36
|
||||
* @since 1.8
|
||||
*/
|
||||
public class LogTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 测试正常打印
|
||||
Log.debug("[1] This is a test.");
|
||||
Log.debug("[1] This is a test.", new NullPointerException("npe"));
|
||||
|
||||
Log.warn("[1] This is a test.");
|
||||
Log.warn("[1] This is a test.", new NullPointerException("npe"));
|
||||
|
||||
Log.error("[1] This is a test.");
|
||||
Log.error("[1] This is a test.", new NullPointerException("npe"));
|
||||
|
||||
// 测试只打印 error级别的日志
|
||||
Log.Config.level = Log.Level.ERROR;
|
||||
|
||||
Log.debug("[2] This is a test.");
|
||||
Log.warn("[2] This is a test.");
|
||||
Log.error("[2] This is a test.");
|
||||
|
||||
// 测试关闭日志
|
||||
Log.Config.enable = false;
|
||||
|
||||
Log.debug("[3] This is a test.");
|
||||
Log.warn("[3] This is a test.");
|
||||
Log.error("[3] This is a test.");
|
||||
}
|
||||
|
||||
/**
|
||||
* 1000000: 23135ms
|
||||
* 100000: 3016ms
|
||||
* 10000: 328ms
|
||||
* 1000: 26ms
|
||||
*/
|
||||
@Test
|
||||
public void testByThread() {
|
||||
long start = System.currentTimeMillis();
|
||||
for (int i = 0; i < 1; i++) {
|
||||
System.out.println(callMethodByThread());
|
||||
}
|
||||
long end = System.currentTimeMillis();
|
||||
System.out.println((end - start) + "ms");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 1000000: 19058ms
|
||||
* 100000: 2772ms
|
||||
* 10000: 323ms
|
||||
* 1000: 29ms
|
||||
*/
|
||||
@Test
|
||||
public void testByThrowable() {
|
||||
long end = System.currentTimeMillis();
|
||||
for (int i = 0; i < 1; i++) {
|
||||
System.out.println(callMethodByThrowable());
|
||||
}
|
||||
long end2 = System.currentTimeMillis();
|
||||
System.out.println((end2 - end) + "ms");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBySecurityManager() {
|
||||
long end = System.currentTimeMillis();
|
||||
for (int i = 0; i < 1; i++) {
|
||||
System.out.println(callMethodBySecurityManager());
|
||||
}
|
||||
long end2 = System.currentTimeMillis();
|
||||
System.out.println((end2 - end) + "ms");
|
||||
|
||||
}
|
||||
|
||||
private String callMethodByThread() {
|
||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||
for (StackTraceElement stackTraceElement : stackTrace) {
|
||||
System.out.println(stackTraceElement.getMethodName());
|
||||
}
|
||||
return stackTrace[2].getMethodName();
|
||||
}
|
||||
|
||||
private String callMethodByThrowable() {
|
||||
StackTraceElement[] stackTrace = (new Throwable()).getStackTrace();
|
||||
for (StackTraceElement stackTraceElement : stackTrace) {
|
||||
System.out.println(stackTraceElement.getMethodName());
|
||||
}
|
||||
return stackTrace[2].getMethodName();
|
||||
}
|
||||
|
||||
private String callMethodBySecurityManager() {
|
||||
return new SecurityManager() {
|
||||
String getClassName() {
|
||||
for (Class clazz : getClassContext()) {
|
||||
System.out.println(clazz);
|
||||
}
|
||||
return getClassContext()[0].getName();
|
||||
}
|
||||
}.getClassName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package me.zhyd.oauth.model;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class AuthUserTest {
|
||||
|
||||
@Test
|
||||
public void serialize() {
|
||||
|
||||
AuthUser user = AuthUser.builder()
|
||||
.nickname("test")
|
||||
.build();
|
||||
String json = JSON.toJSONString(user);
|
||||
Assert.assertEquals(json, "{\"nickname\":\"test\"}");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deserialize() {
|
||||
AuthUser user = AuthUser.builder()
|
||||
.nickname("test")
|
||||
.build();
|
||||
String json = JSON.toJSONString(user);
|
||||
|
||||
AuthUser deserializeUser = JSON.parseObject(json, AuthUser.class);
|
||||
Assert.assertEquals(deserializeUser.getNickname(), "test");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package me.zhyd.oauth.sdk;
|
||||
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @since 1.10.0
|
||||
*/
|
||||
public class ThirdPartSdkTest {
|
||||
|
||||
@Test
|
||||
public void huawei() {
|
||||
String code = "CF1IwmFc6uZABI9Y795BkhXfvHidIFFw04I4Zc4KML4n+vlXxwNUcQKS4xlopjFDpEk6LzQbjwdTNxvjZ9jqnd/1m5nswhx8X7e0/dL2kyGAMVZWFgVq9ClxNN18b+Z0xtfJjkm7bDnfC3W5h4COgTCoLSjiWKSHWp5hCunp6pQRo1FHovZXm13TLNlhF9mCVtJx3kTQ";
|
||||
HttpResponse response = HttpRequest.post("https://oauth-login.cloud.huawei.com/oauth2/v2/token")
|
||||
.form("grant_type", "authorization_code")
|
||||
.form("code", code)
|
||||
.form("client_id", "100994535")
|
||||
.form("client_secret", "22aea400bef603fef26d15a79c806eb477b35de0a529758f2a3b1bda32bfb80d")
|
||||
.form("redirect_uri", "http://127.0.0.1:8443/oauth/callback/huawei")
|
||||
.execute();
|
||||
System.out.println(response.body());
|
||||
|
||||
// {"access_token":"accessToken","expires_in":3600,"refresh_token":"refreshToken","scope":"https:\/\/www.huawei.com\/auth\/account\/base.profile","token_type":"Bearer"}
|
||||
|
||||
//
|
||||
HttpResponse response2 = HttpRequest.post("https://api.vmall.com/rest.php")
|
||||
.form("nsp_ts", System.currentTimeMillis())
|
||||
.form("access_token", JSONObject.parseObject(response.body()).getString("access_token"))
|
||||
.form("nsp_fmt", "JS")
|
||||
// .form("nsp_cb", "_jqjsp")
|
||||
.form("nsp_svc", "OpenUP.User.getInfo")
|
||||
.execute();
|
||||
System.out.println(response2.body());
|
||||
// 华为性别 0是男,女是1
|
||||
// {"gender":1,"headPictureURL":"https://upfile-drcn.platform.hicloud.com/FileServer/image/b.0260086000226601572.20190415065228.iBKdTsqaNkdPXSz4N7pIRWAgeu45ec3k.1000.9A5467309F9284B267ECA33B59D3D7DA4A71BC732D3BB24EC6B880A73DEE9BAB.jpg","languageCode":"zh-CN","userID":"260086000226601572","userName":"151****2326","userState":1,"userValidStatus":1}
|
||||
}
|
||||
}
|
||||
@@ -1,231 +0,0 @@
|
||||
package me.zhyd.oauth.utils;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class AuthStateTest {
|
||||
|
||||
/**
|
||||
* step1 生成state: 预期创建一个新的state...
|
||||
* Z2l0aHViXzE5Mi4xNjguMTkuMV9yM3ll
|
||||
*
|
||||
* step2 重复生成state: 预期从bucket中返回一个可用的state...
|
||||
* Z2l0aHViXzE5Mi4xNjguMTkuMV9yM3ll
|
||||
*
|
||||
* step3 获取state: 预期获取上面生成的state...
|
||||
* Z2l0aHViXzE5Mi4xNjguMTkuMV9yM3ll
|
||||
*
|
||||
* step4 删除state: 预期删除掉上面创建的state...
|
||||
*
|
||||
* step5 重新获取state: 预期返回null...
|
||||
* null
|
||||
*/
|
||||
@Test
|
||||
public void usage() {
|
||||
String source = "github";
|
||||
System.out.println("\nstep1 生成state: 预期创建一个新的state...");
|
||||
String state = AuthState.create(source);
|
||||
System.out.println(state);
|
||||
|
||||
System.out.println("\nstep2 重复生成state: 预期从bucket中返回一个可用的state...");
|
||||
String recreateState = AuthState.create(source);
|
||||
System.out.println(recreateState);
|
||||
Assert.assertEquals(state, recreateState);
|
||||
|
||||
System.out.println("\nstep3 获取state: 预期获取上面生成的state...");
|
||||
String stateByBucket = AuthState.get(source);
|
||||
System.out.println(stateByBucket);
|
||||
Assert.assertEquals(state, stateByBucket);
|
||||
|
||||
System.out.println("\nstep4 删除state: 预期删除掉上面创建的state...");
|
||||
AuthState.delete(source);
|
||||
|
||||
System.out.println("\nstep5 重新获取state: 预期返回null...");
|
||||
String deletedState = AuthState.get(source);
|
||||
System.out.println(deletedState);
|
||||
Assert.assertNull(deletedState);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过随机字符串生成state...
|
||||
* Z2l0aHViXzE5Mi4xNjguMTkuMV9wdnAy
|
||||
*
|
||||
* 通过传入自定义的字符串生成state...
|
||||
* Z2l0aHViXzE5Mi4xNjguMTkuMV/ov5nmmK/kuIDkuKrlrZfnrKbkuLI=
|
||||
*
|
||||
* 通过传入数字生成state...
|
||||
* Z2l0aHViXzE5Mi4xNjguMTkuMV8xMTE=
|
||||
*
|
||||
* 通过传入日期生成state...
|
||||
* Z2l0aHViXzE5Mi4xNjguMTkuMV8xNTQ2MzE1OTMyMDAw
|
||||
*
|
||||
* 通过传入map生成state...
|
||||
* Z2l0aHViXzE5Mi4xNjguMTkuMV97InVzZXJUb2tlbiI6Inh4eHh4IiwidXNlcklkIjoxfQ==
|
||||
*
|
||||
* 通过传入List生成state...
|
||||
* Z2l0aHViXzE5Mi4xNjguMTkuMV9bInh4eHgiLCJ4eHh4eHh4eCJd
|
||||
*
|
||||
* 通过传入实体类生成state...
|
||||
* Z2l0aHViXzE5Mi4xNjguMTkuMV97ImNsaWVudElkIjoieHh4eHgiLCJjbGllbnRTZWNyZXQiOiJ4eHh4eCIsInVuaW9uSWQiOmZhbHNlfQ==
|
||||
*/
|
||||
@Test
|
||||
public void create() {
|
||||
String source = "github";
|
||||
System.out.println("\n通过随机字符串生成state...");
|
||||
String state = AuthState.create(source);
|
||||
System.out.println(state);
|
||||
AuthState.delete(source);
|
||||
|
||||
System.out.println("\n通过传入自定义的字符串生成state...");
|
||||
String stringBody = "这是一个字符串";
|
||||
String stringState = AuthState.create(source, stringBody);
|
||||
System.out.println(stringState);
|
||||
AuthState.delete(source);
|
||||
|
||||
System.out.println("\n通过传入数字生成state...");
|
||||
Integer numberBody = 111;
|
||||
String numberState = AuthState.create(source, numberBody);
|
||||
System.out.println(numberState);
|
||||
AuthState.delete(source);
|
||||
|
||||
System.out.println("\n通过传入日期生成state...");
|
||||
Date dateBody = DateUtil.parse("2019-01-01 12:12:12", DatePattern.NORM_DATETIME_PATTERN);
|
||||
String dateState = AuthState.create(source, dateBody);
|
||||
System.out.println(dateState);
|
||||
AuthState.delete(source);
|
||||
|
||||
System.out.println("\n通过传入map生成state...");
|
||||
Map<String, Object> mapBody = new HashMap<>();
|
||||
mapBody.put("userId", 1);
|
||||
mapBody.put("userToken", "xxxxx");
|
||||
String mapState = AuthState.create(source, mapBody);
|
||||
System.out.println(mapState);
|
||||
AuthState.delete(source);
|
||||
|
||||
System.out.println("\n通过传入List生成state...");
|
||||
List<String> listBody = new ArrayList<>();
|
||||
listBody.add("xxxx");
|
||||
listBody.add("xxxxxxxx");
|
||||
String listState = AuthState.create(source, listBody);
|
||||
System.out.println(listState);
|
||||
AuthState.delete(source);
|
||||
|
||||
System.out.println("\n通过传入实体类生成state...");
|
||||
AuthConfig entityBody = AuthConfig.builder()
|
||||
.clientId("xxxxx")
|
||||
.clientSecret("xxxxx")
|
||||
.build();
|
||||
String entityState = AuthState.create(source, entityBody);
|
||||
System.out.println(entityState);
|
||||
AuthState.delete(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过随机字符串生成state...
|
||||
* Z2l0aHViXzE5Mi4xNjguMTkuMV9kaWNn
|
||||
* dicg
|
||||
*
|
||||
* 通过传入自定义的字符串生成state...
|
||||
* Z2l0aHViXzE5Mi4xNjguMTkuMV/ov5nmmK/kuIDkuKrlrZfnrKbkuLI=
|
||||
* 这是一个字符串
|
||||
*
|
||||
* 通过传入数字生成state...
|
||||
* Z2l0aHViXzE5Mi4xNjguMTkuMV8xMTE=
|
||||
* 111
|
||||
*
|
||||
* 通过传入日期生成state...
|
||||
* Z2l0aHViXzE5Mi4xNjguMTkuMV8xNTQ2MzE1OTMyMDAw
|
||||
* Tue Jan 01 12:12:12 CST 2019
|
||||
*
|
||||
* 通过传入map生成state...
|
||||
* Z2l0aHViXzE5Mi4xNjguMTkuMV97InVzZXJUb2tlbiI6Inh4eHh4IiwidXNlcklkIjoxfQ==
|
||||
* {userToken=xxxxx, userId=1}
|
||||
*
|
||||
* 通过传入List生成state...
|
||||
* Z2l0aHViXzE5Mi4xNjguMTkuMV9bInh4eHgiLCJ4eHh4eHh4eCJd
|
||||
* [xxxx, xxxxxxxx]
|
||||
*
|
||||
* 通过传入实体类生成state...
|
||||
* Z2l0aHViXzE5Mi4xNjguMTkuMV97ImNsaWVudElkIjoieHh4eHgiLCJjbGllbnRTZWNyZXQiOiJ4eHh4eCIsInVuaW9uSWQiOmZhbHNlfQ==
|
||||
* me.zhyd.oauth.config.AuthConfig@725bef66
|
||||
*/
|
||||
@Test
|
||||
public void getBody() {
|
||||
String source = "github";
|
||||
System.out.println("\n通过随机字符串生成state...");
|
||||
String state = AuthState.create(source);
|
||||
System.out.println(state);
|
||||
String body = AuthState.getBody(source, state, String.class);
|
||||
System.out.println(body);
|
||||
AuthState.delete(source);
|
||||
|
||||
System.out.println("\n通过传入自定义的字符串生成state...");
|
||||
String stringBody = "这是一个字符串";
|
||||
String stringState = AuthState.create(source, stringBody);
|
||||
System.out.println(stringState);
|
||||
stringBody = AuthState.getBody(source, stringState, String.class);
|
||||
System.out.println(stringBody);
|
||||
AuthState.delete(source);
|
||||
|
||||
System.out.println("\n通过传入数字生成state...");
|
||||
Integer numberBody = 111;
|
||||
String numberState = AuthState.create(source, numberBody);
|
||||
System.out.println(numberState);
|
||||
numberBody = AuthState.getBody(source, numberState, Integer.class);
|
||||
System.out.println(numberBody);
|
||||
AuthState.delete(source);
|
||||
|
||||
System.out.println("\n通过传入日期生成state...");
|
||||
Date dateBody = DateUtil.parse("2019-01-01 12:12:12", DatePattern.NORM_DATETIME_PATTERN);
|
||||
String dateState = AuthState.create(source, dateBody);
|
||||
System.out.println(dateState);
|
||||
dateBody = AuthState.getBody(source, dateState, Date.class);
|
||||
System.out.println(dateBody);
|
||||
AuthState.delete(source);
|
||||
|
||||
System.out.println("\n通过传入map生成state...");
|
||||
Map<String, Object> mapBody = new HashMap<>();
|
||||
mapBody.put("userId", 1);
|
||||
mapBody.put("userToken", "xxxxx");
|
||||
String mapState = AuthState.create(source, mapBody);
|
||||
System.out.println(mapState);
|
||||
mapBody = AuthState.getBody(source, mapState, Map.class);
|
||||
System.out.println(mapBody);
|
||||
AuthState.delete(source);
|
||||
|
||||
System.out.println("\n通过传入List生成state...");
|
||||
List<String> listBody = new ArrayList<>();
|
||||
listBody.add("xxxx");
|
||||
listBody.add("xxxxxxxx");
|
||||
String listState = AuthState.create(source, listBody);
|
||||
System.out.println(listState);
|
||||
listBody = AuthState.getBody(source, listState, List.class);
|
||||
System.out.println(listBody);
|
||||
AuthState.delete(source);
|
||||
|
||||
System.out.println("\n通过传入实体类生成state...");
|
||||
AuthConfig entityBody = AuthConfig.builder()
|
||||
.clientId("xxxxx")
|
||||
.clientSecret("xxxxx")
|
||||
.build();
|
||||
String entityState = AuthState.create(source, entityBody);
|
||||
System.out.println(entityState);
|
||||
entityBody = AuthState.getBody(source, entityState, AuthConfig.class);
|
||||
System.out.println(entityBody);
|
||||
AuthState.delete(source);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getErrorStateBody() {
|
||||
String source = "github";
|
||||
String state = "1111111111111111111111111111111";
|
||||
String body = AuthState.getBody(source, state, String.class);
|
||||
System.out.println(body);
|
||||
AuthState.delete(source);
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package me.zhyd.oauth.utils;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.JSONPath;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0
|
||||
* @website https://www.zhyd.me
|
||||
* @date 2019/7/19 15:52
|
||||
* @since 1.8
|
||||
*/
|
||||
public class CustomTest {
|
||||
|
||||
/**
|
||||
* 1000000: 23135ms
|
||||
* 100000: 3016ms
|
||||
* 10000: 328ms
|
||||
* 1000: 26ms
|
||||
*/
|
||||
@Test
|
||||
public void test() {
|
||||
long start = System.currentTimeMillis();
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
callMethod();
|
||||
}
|
||||
long end = System.currentTimeMillis();
|
||||
System.out.println((end - start) + "ms");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 1000000: 19058ms
|
||||
* 100000: 2772ms
|
||||
* 10000: 323ms
|
||||
* 1000: 29ms
|
||||
*/
|
||||
@Test
|
||||
public void test2() {
|
||||
long end = System.currentTimeMillis();
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
callMethod2();
|
||||
}
|
||||
long end2 = System.currentTimeMillis();
|
||||
System.out.println((end2 - end) + "ms");
|
||||
|
||||
}
|
||||
|
||||
public String callMethod() {
|
||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||
// for (StackTraceElement stackTraceElement : stackTrace) {
|
||||
// System.out.println(stackTraceElement.getMethodName());
|
||||
// }
|
||||
return stackTrace[2].getMethodName();
|
||||
}
|
||||
|
||||
public String callMethod2() {
|
||||
StackTraceElement[] stackTrace = (new Throwable()).getStackTrace();
|
||||
// for (StackTraceElement stackTraceElement : stackTrace) {
|
||||
// System.out.println(stackTraceElement.getMethodName());
|
||||
// }
|
||||
return stackTrace[2].getMethodName();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsonpath(){
|
||||
List<Map<String, Map<String, Object>>> list = new ArrayList<>();
|
||||
|
||||
Map<String, Map<String, Object>> map = new HashMap<>();
|
||||
Map<String, Object> node = new HashMap<>();
|
||||
node.put("emailAddress", "xxxx");
|
||||
map.put("handle~", node);
|
||||
list.add(map);
|
||||
|
||||
|
||||
Map<String, Object> master = new HashMap<>();
|
||||
// master.put("elements", list);
|
||||
JSONObject emailObj = JSONObject.parseObject(JSON.toJSONString(master));
|
||||
Object object = JSONPath.eval(emailObj, "$['elements'][0]['handle~']['emailAddress']");
|
||||
System.out.println(object);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package me.zhyd.oauth.utils;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.JSONPath;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* JsonPath用法测试
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
*/
|
||||
public class JsonPathTest {
|
||||
|
||||
@Test
|
||||
public void jsonPath() {
|
||||
List<Map<String, Map<String, Object>>> list = new ArrayList<>();
|
||||
|
||||
Map<String, Map<String, Object>> map = new HashMap<>();
|
||||
Map<String, Object> node = new HashMap<>();
|
||||
node.put("emailAddress", "xxxx");
|
||||
map.put("handle~", node);
|
||||
list.add(map);
|
||||
|
||||
|
||||
Map<String, Object> master = new HashMap<>();
|
||||
// master.put("elements", list);
|
||||
JSONObject emailObj = JSONObject.parseObject(JSON.toJSONString(master));
|
||||
Object object = JSONPath.eval(emailObj, "$['elements'][0]['handle~']['emailAddress']");
|
||||
System.out.println(object);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package me.zhyd.oauth.utils;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
public class StringUtilsTest {
|
||||
@Rule
|
||||
public final ExpectedException thrown =
|
||||
ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void isEmptyNonEmptyInput() {
|
||||
Assert.assertFalse(StringUtils.isEmpty("non-empty string"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isEmptyEmptyInput() {
|
||||
Assert.assertTrue(StringUtils.isEmpty(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isEmptyInputNull() {
|
||||
Assert.assertTrue(StringUtils.isEmpty(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isNotEmptyNonEmptyInput() {
|
||||
Assert.assertTrue(StringUtils.isNotEmpty("non-empty string"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isNotEmptyEmptyInput() {
|
||||
Assert.assertFalse(StringUtils.isNotEmpty(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isNotEmptyInputNull() {
|
||||
Assert.assertFalse(StringUtils.isNotEmpty(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendIfNotContainAppendedStringNotPresent() {
|
||||
// (Check the case where appendStr doesn't occur in str)
|
||||
final String str = "Prefix ";
|
||||
final String appendStr = "suffix";
|
||||
final String otherwise = "should be discarded";
|
||||
|
||||
final String result =
|
||||
StringUtils.appendIfNotContain(str, appendStr, otherwise);
|
||||
|
||||
Assert.assertEquals("Prefix suffix", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendIfNotContainAppendedStringPresent() {
|
||||
// (Check the case where appendStr occurs in str)
|
||||
final String str = "Prefix ";
|
||||
final String appendStr = "Prefix";
|
||||
final String otherwise = "should be appended";
|
||||
|
||||
final String result =
|
||||
StringUtils.appendIfNotContain(str, appendStr, otherwise);
|
||||
|
||||
Assert.assertEquals("Prefix should be appended", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendIfNotContainEmptyString() {
|
||||
// (Check the special-case for str being empty)
|
||||
final String str = "";
|
||||
final String appendStr = "should not be appended";
|
||||
final String otherwise = "should also not be appended";
|
||||
|
||||
final String result =
|
||||
StringUtils.appendIfNotContain(str, appendStr, otherwise);
|
||||
|
||||
Assert.assertEquals("", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendIfNotContainAppendingEmptyString() {
|
||||
// (Check the special-case for appendStr being empty)
|
||||
final String str = "should be kept";
|
||||
final String appendStr = "";
|
||||
final String otherwise = "should also not be appended";
|
||||
|
||||
final String result =
|
||||
StringUtils.appendIfNotContain(str, appendStr, otherwise);
|
||||
|
||||
Assert.assertEquals("should be kept", result);
|
||||
}
|
||||
}
|
||||
@@ -21,18 +21,43 @@ public class UrlBuilderTest {
|
||||
.clientId("appid-110110110")
|
||||
.clientSecret("secret-110110110")
|
||||
.redirectUri("https://xkcoding.com")
|
||||
.state(AuthState.create(AuthSource.WECHAT))
|
||||
.build();
|
||||
String build = UrlBuilder.fromBaseUrl(AuthSource.WECHAT.authorize())
|
||||
.queryParam("appid", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("scope", "snsapi_login")
|
||||
.queryParam("state", config.getState().concat("#wechat_redirect"))
|
||||
.queryParam("state", "")
|
||||
.build(false);
|
||||
System.out.println(build);
|
||||
AuthWeChatRequest request = new AuthWeChatRequest(config);
|
||||
String authorize = request.authorize();
|
||||
Assert.assertEquals(build, authorize);
|
||||
AuthState.delete(AuthSource.WECHAT);
|
||||
String authorize = request.authorize("state");
|
||||
System.out.println(authorize);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void build() {
|
||||
String url = UrlBuilder.fromBaseUrl("https://www.zhyd.me")
|
||||
.queryParam("name", "yadong.zhang")
|
||||
.build();
|
||||
Assert.assertEquals(url, "https://www.zhyd.me?name=yadong.zhang");
|
||||
|
||||
url = UrlBuilder.fromBaseUrl(url)
|
||||
.queryParam("github", "https://github.com/zhangyd-c")
|
||||
.build();
|
||||
Assert.assertEquals(url, "https://www.zhyd.me?name=yadong.zhang&github=https://github.com/zhangyd-c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void build1() {
|
||||
String url = UrlBuilder.fromBaseUrl("https://www.zhyd.me")
|
||||
.queryParam("name", "yadong.zhang")
|
||||
.build(true);
|
||||
Assert.assertEquals(url, "https://www.zhyd.me?name=yadong.zhang");
|
||||
|
||||
url = UrlBuilder.fromBaseUrl(url)
|
||||
.queryParam("github", "https://github.com/zhangyd-c")
|
||||
.build(true);
|
||||
Assert.assertEquals(url, "https://www.zhyd.me?name=yadong.zhang&github=https%3A%2F%2Fgithub.com%2Fzhangyd-c");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package me.zhyd.oauth.utils;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class UuidUtilsTest {
|
||||
|
||||
@Test
|
||||
public void getUUID() {
|
||||
|
||||
String uuid = UuidUtils.getUUID();
|
||||
System.out.println(uuid);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user