Compare commits
135 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a75bac2cf7 | |||
| 666d50b461 | |||
| 7515301f50 | |||
| cab222059c | |||
| 798e7556ba | |||
| 1244524da0 | |||
| ce1f71c707 | |||
| 93c301e05b | |||
| 53df992474 | |||
| e29df531fa | |||
| 3a04098e4c | |||
| 81691a3462 | |||
| 6708525d99 | |||
| a599ced6b0 | |||
| f815f12acc | |||
| 78cb32a9f2 | |||
| 6505df15a7 | |||
| d7d87c7f04 | |||
| 188e98c0f2 | |||
| f2fb942808 | |||
| d1d7587f4e | |||
| d5e60165c0 | |||
| d5189aa30c | |||
| 32c540cf1e | |||
| 9aa693d2da | |||
| 0d4e52d615 | |||
| 72792c3c83 | |||
| a6f25ec312 | |||
| 6dc42ac8b3 | |||
| b67483c263 | |||
| 66ee684e1f | |||
| d0375ce31a | |||
| 698c922b6b | |||
| 5694d48288 | |||
| 44d4323fb2 | |||
| f7561e97fc | |||
| e8cadef4ce | |||
| 49f169abb9 | |||
| 917239a89a | |||
| 5a5827a705 | |||
| 27583b15cc | |||
| 090d7d3662 | |||
| b5d8dbaede | |||
| a5da3b9765 | |||
| ae1b5815d8 | |||
| 350f9d70ae | |||
| 0ed3092d53 | |||
| 8d1f700e7f | |||
| d977e05a3d | |||
| abcdc105e0 | |||
| 267200c434 | |||
| e0242f9929 | |||
| 59b5ba5a1b | |||
| 12c6930182 | |||
| a518e8c0cb | |||
| 4c1fdfc62d | |||
| dc74501b1b | |||
| 8a4861075e | |||
| 65334d0f3f | |||
| 67c668b740 | |||
| 7fe8a4d4bb | |||
| 4f272348da | |||
| ec31b7cbf7 | |||
| 6b196456a1 | |||
| af723a8b08 | |||
| 1360db60ae | |||
| 8d1b329c63 | |||
| 47971438c7 | |||
| e2e1a082d1 | |||
| 3b80e11824 | |||
| 44bb03d63f | |||
| bfe2122962 | |||
| fa2b9114d1 | |||
| 93bee4f5d9 | |||
| 5c0b8eb94a | |||
| e03088a9b4 | |||
| 41a52767b3 | |||
| 88048b7637 | |||
| 186ee58b72 | |||
| fa51358072 | |||
| 80329c2496 | |||
| 78988555b0 | |||
| ac4ede74bf | |||
| 9941ce7e2a | |||
| 4f594a4178 | |||
| b9268f296b | |||
| 1c30f6ab2f | |||
| af7baa924c | |||
| 9902e7eb0d | |||
| 739fa786ce | |||
| 6f1cead802 | |||
| 374b71e5fe | |||
| 9d1ab36e21 | |||
| b8d9f2ebc9 | |||
| c201a9ac90 | |||
| 12ec6226bc | |||
| 9a62332f30 | |||
| a962c96a2c | |||
| d442018c02 | |||
| 8d6d4533e4 | |||
| 2f88c23405 | |||
| cf74f811fa | |||
| bb613010dc | |||
| 7ace410351 | |||
| 65daa0592a | |||
| 25424023c4 | |||
| 67579bfb07 | |||
| 458de3840d | |||
| 1c1d2dc9db | |||
| f5de7f93b5 | |||
| dcf5f30e61 | |||
| e534a4b62e | |||
| 42ede32fc5 | |||
| c0dd700b0a | |||
| f32c341b63 | |||
| 82358cbddb | |||
| 56df9bc1b0 | |||
| 438660621e | |||
| 937fba37f5 | |||
| fde490a205 | |||
| da23fcd54c | |||
| 36b5f333a4 | |||
| d5e0ff3f33 | |||
| b3aee449a2 | |||
| f3619f48fe | |||
| e92f8961f5 | |||
| a6ed65ce3d | |||
| 132c682673 | |||
| 4d92794b1a | |||
| ae9edffc70 | |||
| 7a6ff6c8e5 | |||
| b9ca048d1c | |||
| a07dcbd26f | |||
| 3f67757a3a | |||
| c951ffad59 |
@@ -0,0 +1,19 @@
|
|||||||
|
# JustAuth 开发组IDE 编辑器标准
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# 空格替代Tab缩进在各种编辑工具下效果一致
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.java]
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
insert_final_newline = false
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a target="_blank" href="https://search.maven.org/search?q=JustAuth">
|
<a target="_blank" href="https://search.maven.org/search?q=JustAuth">
|
||||||
<img src="https://img.shields.io/badge/Maven Central-1.3.1-blue.svg" ></img>
|
<img src="https://img.shields.io/badge/Maven Central-1.9.2-blue.svg" ></img>
|
||||||
</a>
|
</a>
|
||||||
<a target="_blank" href="https://gitee.com/yadong.zhang/JustAuth/blob/master/LICENSE">
|
<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>
|
<img src="https://img.shields.io/apm/l/vim-mode.svg?color=yellow" ></img>
|
||||||
@@ -14,25 +14,41 @@
|
|||||||
<a target="_blank" href="https://www.oracle.com/technetwork/java/javase/downloads/index.html">
|
<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>
|
<img src="https://img.shields.io/badge/JDK-1.8+-green.svg" ></img>
|
||||||
</a>
|
</a>
|
||||||
|
<a target="_blank" href="https://apidoc.gitee.com/yadong.zhang/JustAuth/">
|
||||||
|
<img src="https://img.shields.io/badge/Docs-1.9.2-orange.svg" ></img>
|
||||||
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<center>
|
<center>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td align="center" width="200"><a href="#授权gitee"><img src="https://gitee.com/logo_icon.png" width="20"></a></td>
|
<td align="center" width="200"><a href="#授权gitee"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/gitee.png" width="20"></a></td>
|
||||||
<td align="center" width="200"><a href="#授权github"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/github.png" width="20"></a></td>
|
<td align="center" width="200"><a href="#授权github"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/github.png" width="20"></a></td>
|
||||||
<td align="center" width="200"><a href="#授权weibo"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/weibo.png" width="20"></a></td>
|
<td align="center" width="200"><a href="#授权weibo"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/weibo.png" width="20"></a></td>
|
||||||
<td align="center" width="200"><a href="#授权钉钉"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/dingding.png" width="20"></a></td>
|
<td align="center" width="200"><a href="#授权钉钉"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/dingtalk.png" width="20"></a></td>
|
||||||
<td align="center" width="200"><a href="#授权百度"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/baidu.png" width="20"></a></td>
|
<td align="center" width="200"><a href="#授权百度"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/baidu.png" width="20"></a></td>
|
||||||
<td align="center" width="200"><a href="#授权coding"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/coding.png" width="20"></a></td>
|
<td align="center" width="200"><a href="#授权coding"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/coding.png" width="20"></a></td>
|
||||||
<td align="center" width="200"><a href="#授权腾讯云开发者平台"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/tencent_cloud.png" width="20"></a></td>
|
<td align="center" width="200"><a href="#授权腾讯云开发者平台"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/tencentCloud.png" width="20"></a></td>
|
||||||
<td align="center" width="200"><a href="#授权oschina"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/oschinas.png" width="20"></a></td>
|
<td align="center" width="200"><a href="#授权oschina"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/oschina.png" width="20"></a></td>
|
||||||
<td align="center" width="200"><a href="#授权支付宝"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/alipay.png" width="20"></a></td>
|
<td align="center" width="200"><a href="#授权支付宝"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/alipay.png" width="20"></a></td>
|
||||||
<td align="center" width="200"><a href="#授权qq"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/qq.png" width="20"></a></td>
|
<td align="center" width="200"><a href="#授权qq"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/qq.png" width="20"></a></td>
|
||||||
<td align="center" width="200"><a href="#授权微信"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/wechats.png" width="20"></a></td>
|
<td align="center" width="200"><a href="#授权微信"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/wechat.png" width="20"></a></td>
|
||||||
<td align="center" width="200"><a href="#授权淘宝"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/taobao.png" width="20"></a></td>
|
<td align="center" width="200"><a href="#授权淘宝"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/taobao.png" width="20"></a></td>
|
||||||
<td align="center" width="200"><a href="#授权google"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/google.png" width="20"></a></td>
|
<td align="center" width="200"><a href="#授权google"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/google.png" width="20"></a></td>
|
||||||
<td align="center" width="200"><a href="#授权facebook"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/facebook.png" width="20"></a></td>
|
<td align="center" width="200"><a href="#授权facebook"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/facebook.png" width="20"></a></td>
|
||||||
|
<td align="center" width="200"><a href="#授权抖音"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/douyin.png" width="20"></a></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td align="center" width="200"><a href="#授权领英"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/linkedin.png" width="20"></a></td>
|
||||||
|
<td align="center" width="200"><a href="#授权微软"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/microsoft.png" width="20"></a></td>
|
||||||
|
<td align="center" width="200"><a href="#授权小米"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/mi.png" width="20"></a></td>
|
||||||
|
<td align="center" width="200"><a href="#授权今日头条"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/toutiao.png" width="20"></a></td>
|
||||||
|
<td align="center" width="200"><a href="#授权Teambition"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/teambition.png" width="20"></a></td>
|
||||||
|
<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="#授权csdn"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/csdn.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>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -46,13 +62,21 @@ JustAuth,如你所见,它仅仅是一个**第三方授权登录**的**工具
|
|||||||
|
|
||||||
项目开源地址:[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)
|
||||||
|
|
||||||
|
## 特点
|
||||||
|
|
||||||
|
废话不多说,就俩字:
|
||||||
|
|
||||||
|
1. **全**:已集成十多家第三方平台(国内外常用的基本都已包含),后续依然还有扩展计划!
|
||||||
|
2. **简**:API就是奔着最简单去设计的(见后面`快速开始`),尽量让您用起来没有障碍感!
|
||||||
|
|
||||||
## 快速开始
|
## 快速开始
|
||||||
|
|
||||||
- 引入依赖
|
- 引入依赖
|
||||||
```xml
|
```xml
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>me.zhyd.oauth</groupId>
|
<groupId>me.zhyd.oauth</groupId>
|
||||||
<artifactId>JustAuth</artifactId>
|
<artifactId>JustAuth</artifactId>
|
||||||
<version>1.3.2</version>
|
<version>1.9.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
- 调用api
|
- 调用api
|
||||||
@@ -62,37 +86,52 @@ AuthRequest authRequest = new AuthGiteeRequest(AuthConfig.builder()
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
|
.state("state")
|
||||||
.build());
|
.build());
|
||||||
// 生成授权页面
|
// 生成授权页面
|
||||||
authRequest.authorize();
|
authRequest.authorize();
|
||||||
// 授权登录后会返回一个code,用这个code进行登录
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的参数
|
||||||
authRequest.login("code");
|
authRequest.login(callback);
|
||||||
```
|
```
|
||||||
|
|
||||||
**配套Demo**:[JustAuth-demo](https://gitee.com/yadong.zhang/JustAuth-demo)
|
注:`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)
|
||||||
|
|
||||||
具体的例子可以参考:
|
具体的例子可以参考:
|
||||||
|
|
||||||
- [实现Gitee授权登录](http://t.cn/ExDKxQs)
|
- [实现Gitee授权登录](http://t.cn/ExDKxQs)
|
||||||
- [实现Github授权登录](http://t.cn/EJ0Fxqo)
|
- [实现Github授权登录](http://t.cn/EJ0Fxqo)
|
||||||
|
- [Spring Boot 快速集成第三方登录功能](http://t.cn/AiWWx5kH)
|
||||||
|
|
||||||
#### API列表
|
#### API列表
|
||||||
| :computer: 平台 | :coffee: API类 | :page_facing_up: SDK |
|
| :computer: 平台 | :coffee: API类 | :page_facing_up: SDK |
|
||||||
|:------:|:-------:|:-------:|
|
|:------:|:-------:|:-------:|
|
||||||
| <img src="https://gitee.com/logo_icon.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/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://github.com/settings/developers" 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/%E5%BE%AE%E5%8D%9AAPI" 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/dingding.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/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="https://developer.baidu.com/" 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/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/tencent_cloud.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/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/oschinas.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/openapi_user" 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/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="http://wiki.connect.qq.com/" 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/wechats.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/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/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/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/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/csdn.png" width="20"> | [AuthCsdnRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthCsdnRequest.java) | 无 |
|
| <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登录只能针对少部分用户使用了_
|
_请知悉:经咨询CSDN官方客服得知,CSDN的授权开放平台已经下线。如果以前申请过的应用,可以继续使用,但是不再支持申请新的应用。so, 本项目中的CSDN登录只能针对少部分用户使用了_
|
||||||
@@ -109,7 +148,7 @@ _请知悉:经咨询CSDN官方客服得知,CSDN的授权开放平台已经
|
|||||||
2. 把fork过去的项目也就是你仓库中的项目clone到你的本地
|
2. 把fork过去的项目也就是你仓库中的项目clone到你的本地
|
||||||
3. 修改代码
|
3. 修改代码
|
||||||
4. commit后push到自己的库
|
4. commit后push到自己的库
|
||||||
5. 发起PR(pull request) 请求
|
5. 发起PR(pull request) 请求,提交到`dev`分支
|
||||||
6. 等待作者合并
|
6. 等待作者合并
|
||||||
|
|
||||||
## 致谢
|
## 致谢
|
||||||
@@ -118,69 +157,11 @@ _请知悉:经咨询CSDN官方客服得知,CSDN的授权开放平台已经
|
|||||||
|
|
||||||
[YurunOAuthLogin](https://gitee.com/yurunsoft/YurunOAuthLogin): PHP 第三方登录授权 SDK
|
[YurunOAuthLogin](https://gitee.com/yurunsoft/YurunOAuthLogin): PHP 第三方登录授权 SDK
|
||||||
|
|
||||||
|
[阿里妈妈MUX倾力打造的矢量图标库-iconfont](https://www.iconfont.cn/search/index): 本文档中的图标大部分取自该平台
|
||||||
|
|
||||||
## 参考授权图例
|
## 关于OAuth
|
||||||
|
|
||||||
#### 授权gitee
|
[The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749)
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### 授权github
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### 授权weibo
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### 授权钉钉
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### 授权百度
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### 授权coding
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### 授权腾讯云开发者平台
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### 授权oschina
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### 授权支付宝
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### 授权qq
|
|
||||||
|
|
||||||
待续
|
|
||||||
|
|
||||||
#### 授权微信
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### 授权淘宝
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
#### 授权Google
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### 授权Facebook
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### 授权csdn
|
|
||||||
|
|
||||||
_请知悉:经咨询CSDN官方客服得知,CSDN的授权开放平台已经下线。如果以前申请过的应用,可以继续使用,但是不再支持申请新的应用。so, 本项目中的CSDN登录只能针对少部分用户使用了_
|
|
||||||
|
|
||||||
## 关注&交流
|
## 关注&交流
|
||||||
|
|
||||||
@@ -189,7 +170,7 @@ _请知悉:经咨询CSDN官方客服得知,CSDN的授权开放平台已经
|
|||||||
| <img src="https://gitee.com/yadong.zhang/static/raw/master/wx/wechat_account.jpg" width="200" /> | <img src="https://gitee.com/yadong.zhang/static/raw/master/wx/wx.png" width="170"/> |
|
| <img src="https://gitee.com/yadong.zhang/static/raw/master/wx/wechat_account.jpg" width="200" /> | <img src="https://gitee.com/yadong.zhang/static/raw/master/wx/wx.png" width="170"/> |
|
||||||
|
|
||||||
**QQ群**
|
**QQ群**
|
||||||
|
|
||||||
- JustAuth交流群 (230017570):专业交流该项目
|
- JustAuth交流群 (230017570):专业交流该项目
|
||||||
|
|
||||||
- 开源总群 (190886500):各个开源项目的都有,也有博客建设等方面的朋友。(注意,该群需付费进入,防止发垃圾广告、垃圾推广等人士)
|
- 开源总群 (190886500):各个开源项目的都有,也有博客建设等方面的朋友。(注意,该群需付费进入,防止发垃圾广告、垃圾推广等人士)
|
||||||
@@ -197,6 +178,6 @@ _请知悉:经咨询CSDN官方客服得知,CSDN的授权开放平台已经
|
|||||||
|
|
||||||
## 请喝咖啡
|
## 请喝咖啡
|
||||||
|
|
||||||
| 支付宝 | 微信 |
|
| 支付宝 | 微信 |
|
||||||
| :------------: | :------------: |
|
| :------------: | :------------: |
|
||||||
| <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" /> |
|
| <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,7 @@
|
|||||||
|
# 项目贡献者名单
|
||||||
|
|
||||||
|
- <img src="https://avatar.gitee.com/uploads/99/784199_yadong.zhang.png!avatar100?1462325358" width="20"> · yadong.zhang : <a href="https://github.com/zhangyd-c" target="_blank">[Github]</a> | <a href="https://gitee.com/yadong.zhang" target="_blank">[Gitee]</a> | <a href="https://www.zhyd.me" target="_blank">[个人网站]</a>
|
||||||
|
- <img src="https://avatars0.githubusercontent.com/u/10429917?s=460&v=4" width="20"> · yangkai.shen : <a href="https://github.com/xkcoding" target="_blank">[Github]</a> | <a href="https://xkcoding.com" target="_blank">[个人网站]</a>
|
||||||
|
- <img src="https://avatar.gitee.com/uploads/51/1651_dolphinboy.png!avatar100?1479346570" width="20"> · skqing : <a href="https://gitee.com/skqing" target="_blank">[Gitee]</a> | <a href="https://my.oschina.net/dolphinboy" target="_blank">[个人网站]</a>
|
||||||
|
- <img src="https://avatars2.githubusercontent.com/u/2988765?s=115&v=4" width="20"> · pengisgood : <a href="https://github.com/pengisgood" target="_blank">[Github]</a> | <a href="https://pengisgood.github.io" target="_blank">[个人网站]</a>
|
||||||
|
- 千年等一回,我只为等你...
|
||||||
+107
@@ -0,0 +1,107 @@
|
|||||||
|
## 各平台授权页面示例
|
||||||
|
|
||||||
|
_注:非全部平台,部分平台可能不存在图例_
|
||||||
|
|
||||||
|
#### 授权gitee
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 授权github
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 授权weibo
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 授权钉钉
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 授权百度
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 授权coding
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 授权腾讯云开发者平台
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 授权oschina
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 授权支付宝
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 授权qq
|
||||||
|
|
||||||
|
暂无
|
||||||
|
|
||||||
|
#### 授权微信
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 授权淘宝
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
#### 授权Google
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 授权Facebook
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 授权抖音
|
||||||
|
|
||||||
|
暂无
|
||||||
|
|
||||||
|
#### 授权领英
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
#### 授权微软
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 授权小米
|
||||||
|
|
||||||
|
暂无
|
||||||
|
|
||||||
|
#### 授权今日头条
|
||||||
|
|
||||||
|
暂无
|
||||||
|
|
||||||
|
#### 授权Teambition
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 授权Pinterest
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 授权Renren
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 授权Stack Overflow
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### 授权Twitter
|
||||||
|
|
||||||
|
暂无
|
||||||
|
|
||||||
|
#### 授权csdn
|
||||||
|
|
||||||
|
暂无
|
||||||
|
|
||||||
|
_请知悉:经咨询CSDN官方客服得知,CSDN的授权开放平台已经下线。如果以前申请过的应用,可以继续使用,但是不再支持申请新的应用。so, 本项目中的CSDN登录只能针对少部分用户使用了_
|
||||||
@@ -6,11 +6,14 @@
|
|||||||
|
|
||||||
<groupId>me.zhyd.oauth</groupId>
|
<groupId>me.zhyd.oauth</groupId>
|
||||||
<artifactId>JustAuth</artifactId>
|
<artifactId>JustAuth</artifactId>
|
||||||
<version>1.3.3</version>
|
<version>1.9.2</version>
|
||||||
|
|
||||||
<name>JustAuth</name>
|
<name>JustAuth</name>
|
||||||
<url>https://gitee.com/yadong.zhang/JustAuth</url>
|
<url>https://gitee.com/yadong.zhang/JustAuth</url>
|
||||||
<description>史上最全的整合第三方登录的工具, Just Auth</description>
|
<description>
|
||||||
|
史上最全的整合第三方登录的工具,目前已支持Github、Gitee、微博、钉钉、百度、Coding、腾讯云开发者平台、OSChina、支付宝、QQ、微信、淘宝、Google、Facebook、抖音、领英、小米、微软和今日头条等第三方平台的授权登录。
|
||||||
|
Login, so easy!
|
||||||
|
</description>
|
||||||
|
|
||||||
<licenses>
|
<licenses>
|
||||||
<license>
|
<license>
|
||||||
@@ -27,7 +30,7 @@
|
|||||||
|
|
||||||
<developers>
|
<developers>
|
||||||
<developer>
|
<developer>
|
||||||
<name>yadong.zhang</name>
|
<name>Yadong.Zhang</name>
|
||||||
<email>yadong.zhang0415@gmail.com</email>
|
<email>yadong.zhang0415@gmail.com</email>
|
||||||
<url>https://www.zhyd.me</url>
|
<url>https://www.zhyd.me</url>
|
||||||
</developer>
|
</developer>
|
||||||
@@ -36,6 +39,11 @@
|
|||||||
<email>shenyangkai1994@gmail.com</email>
|
<email>shenyangkai1994@gmail.com</email>
|
||||||
<url>https://xkcoding.com</url>
|
<url>https://xkcoding.com</url>
|
||||||
</developer>
|
</developer>
|
||||||
|
<developer>
|
||||||
|
<name>Hongwei.Peng</name>
|
||||||
|
<email>pengisgood@gmail.com</email>
|
||||||
|
<url>https://github.com/pengisgood</url>
|
||||||
|
</developer>
|
||||||
</developers>
|
</developers>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
@@ -46,13 +54,12 @@
|
|||||||
<maven-source.version>2.2.1</maven-source.version>
|
<maven-source.version>2.2.1</maven-source.version>
|
||||||
<maven-compiler.version>3.7.0</maven-compiler.version>
|
<maven-compiler.version>3.7.0</maven-compiler.version>
|
||||||
<maven.test.skip>true</maven.test.skip>
|
<maven.test.skip>true</maven.test.skip>
|
||||||
<hutool-version>4.1.21</hutool-version>
|
<hutool-version>4.5.15</hutool-version>
|
||||||
<lombok-version>1.18.4</lombok-version>
|
<lombok-version>1.18.4</lombok-version>
|
||||||
<junit-version>4.11</junit-version>
|
<junit-version>4.11</junit-version>
|
||||||
<fastjson-version>1.2.44</fastjson-version>
|
<fastjson-version>1.2.58</fastjson-version>
|
||||||
<google-api-version>1.28.0</google-api-version>
|
|
||||||
<guava-version>27.1-jre</guava-version>
|
|
||||||
<alipay-sdk-version>3.7.4.ALL</alipay-sdk-version>
|
<alipay-sdk-version>3.7.4.ALL</alipay-sdk-version>
|
||||||
|
<slf4j-version>1.7.25</slf4j-version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -77,18 +84,17 @@
|
|||||||
<artifactId>fastjson</artifactId>
|
<artifactId>fastjson</artifactId>
|
||||||
<version>${fastjson-version}</version>
|
<version>${fastjson-version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!--<dependency>
|
|
||||||
<groupId>com.google.api-client</groupId>
|
|
||||||
<artifactId>google-api-client</artifactId>
|
|
||||||
<version>${google-api-version}</version>
|
|
||||||
</dependency>-->
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alipay.sdk</groupId>
|
<groupId>com.alipay.sdk</groupId>
|
||||||
<artifactId>alipay-sdk-java</artifactId>
|
<artifactId>alipay-sdk-java</artifactId>
|
||||||
<version>${alipay-sdk-version}</version>
|
<version>${alipay-sdk-version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
<version>${slf4j-version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@@ -117,12 +123,10 @@
|
|||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
<!-- Javadoc -->
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
</plugin>
|
</plugin>
|
||||||
<!-- GPG -->
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-gpg-plugin</artifactId>
|
<artifactId>maven-gpg-plugin</artifactId>
|
||||||
@@ -134,7 +138,6 @@
|
|||||||
<id>release</id>
|
<id>release</id>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<!-- Source -->
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-source-plugin</artifactId>
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
@@ -149,7 +152,6 @@
|
|||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
<!-- Javadoc -->
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
@@ -162,7 +164,6 @@
|
|||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
<!-- GPG -->
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-gpg-plugin</artifactId>
|
<artifactId>maven-gpg-plugin</artifactId>
|
||||||
@@ -189,4 +190,4 @@
|
|||||||
</distributionManagement>
|
</distributionManagement>
|
||||||
</profile>
|
</profile>
|
||||||
</profiles>
|
</profiles>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
package me.zhyd.oauth.authorization;
|
|
||||||
|
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 支付宝授权
|
|
||||||
*
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public class AlipayAuthorization implements Authorization {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAuthorizeUrl(AuthConfig config) {
|
|
||||||
return UrlBuilder.getAlipayAuthorizeUrl(config.getClientId(), config.getRedirectUri());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package me.zhyd.oauth.authorization;
|
|
||||||
|
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 授权接口,用来获取具体第三方平台的授权地址
|
|
||||||
*
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public interface Authorization {
|
|
||||||
|
|
||||||
String getAuthorizeUrl(AuthConfig config);
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
package me.zhyd.oauth.authorization;
|
|
||||||
|
|
||||||
import me.zhyd.oauth.exception.AuthException;
|
|
||||||
import me.zhyd.oauth.model.AuthSource;
|
|
||||||
import me.zhyd.oauth.request.ResponseStatus;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 授权工厂类,负责创建指定平台的授权类获取授权地址
|
|
||||||
* <p>
|
|
||||||
* 使用策略模式 + 工厂模式 避免大量的if else(swatch)操作
|
|
||||||
*
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public class AuthorizationFactory {
|
|
||||||
|
|
||||||
private static Map<String, Authorization> authorizationMap = new HashMap<>();
|
|
||||||
private static boolean loader = false;
|
|
||||||
|
|
||||||
private AuthorizationFactory() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据第三方平台,获取具体的授权工具
|
|
||||||
*
|
|
||||||
* @param source 平台
|
|
||||||
* @return 具体的Authorization
|
|
||||||
*/
|
|
||||||
public static Authorization getAuthorize(AuthSource source) {
|
|
||||||
if (null == source) {
|
|
||||||
throw new AuthException(ResponseStatus.NO_AUTH_SOURCE);
|
|
||||||
}
|
|
||||||
registerAllAuthorize();
|
|
||||||
|
|
||||||
Authorization authorization = authorizationMap.get(source.toString());
|
|
||||||
if (null == authorization) {
|
|
||||||
throw new AuthException(ResponseStatus.UNIDENTIFIED_PLATFORM);
|
|
||||||
}
|
|
||||||
return authorization;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将所有Authorize的实现类注册到authorizeMap中,
|
|
||||||
* 每次增加新的平台都需要在这儿添加注册代码
|
|
||||||
*/
|
|
||||||
private static void registerAllAuthorize() {
|
|
||||||
if (loader) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
AuthorizationFactory.register(AuthSource.ALIPAY, new AlipayAuthorization());
|
|
||||||
AuthorizationFactory.register(AuthSource.BAIDU, new BaiduAuthorization());
|
|
||||||
AuthorizationFactory.register(AuthSource.CODING, new CodingAuthorization());
|
|
||||||
AuthorizationFactory.register(AuthSource.CSDN, new CsdnAuthorization());
|
|
||||||
AuthorizationFactory.register(AuthSource.DINGTALK, new DingTalkAuthorization());
|
|
||||||
AuthorizationFactory.register(AuthSource.GITEE, new GiteeAuthorization());
|
|
||||||
AuthorizationFactory.register(AuthSource.GITHUB, new GithubAuthorization());
|
|
||||||
AuthorizationFactory.register(AuthSource.GOOGLE, new GoogleAuthorization());
|
|
||||||
AuthorizationFactory.register(AuthSource.OSCHINA, new OschinaAuthorization());
|
|
||||||
AuthorizationFactory.register(AuthSource.QQ, new QqAuthorization());
|
|
||||||
AuthorizationFactory.register(AuthSource.TAOBAO, new TaobaoAuthorization());
|
|
||||||
AuthorizationFactory.register(AuthSource.TENCEN_CLOUD, new TencentCloudAuthorization());
|
|
||||||
AuthorizationFactory.register(AuthSource.WECHAT, new WeChatAuthorization());
|
|
||||||
AuthorizationFactory.register(AuthSource.WEIBO, new WeiboAuthorization());
|
|
||||||
AuthorizationFactory.register(AuthSource.FACEBOOK, new FacebookAuthorization());
|
|
||||||
loader = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void register(AuthSource authSource, Authorization authorization) {
|
|
||||||
authorizationMap.put(authSource.toString(), authorization);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package me.zhyd.oauth.authorization;
|
|
||||||
|
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 百度授权
|
|
||||||
*
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public class BaiduAuthorization implements Authorization {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAuthorizeUrl(AuthConfig config) {
|
|
||||||
return UrlBuilder.getBaiduAuthorizeUrl(config.getClientId(), config.getRedirectUri());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package me.zhyd.oauth.authorization;
|
|
||||||
|
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Coding授权
|
|
||||||
*
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public class CodingAuthorization implements Authorization {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAuthorizeUrl(AuthConfig config) {
|
|
||||||
return UrlBuilder.getCodingAuthorizeUrl(config.getClientId(), config.getRedirectUri());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package me.zhyd.oauth.authorization;
|
|
||||||
|
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CSDN授权
|
|
||||||
*
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public class CsdnAuthorization implements Authorization {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAuthorizeUrl(AuthConfig config) {
|
|
||||||
return UrlBuilder.getCsdnAuthorizeUrl(config.getClientId(), config.getRedirectUri());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package me.zhyd.oauth.authorization;
|
|
||||||
|
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 钉钉授权
|
|
||||||
*
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public class DingTalkAuthorization implements Authorization {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAuthorizeUrl(AuthConfig config) {
|
|
||||||
return UrlBuilder.getDingTalkQrConnectUrl(config.getClientId(), config.getRedirectUri());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package me.zhyd.oauth.authorization;
|
|
||||||
|
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Facebook授权
|
|
||||||
*
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.3
|
|
||||||
* @since 1.3
|
|
||||||
*/
|
|
||||||
public class FacebookAuthorization implements Authorization {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAuthorizeUrl(AuthConfig config) {
|
|
||||||
return UrlBuilder.getFacebookAuthorizeUrl(config.getClientId(), config.getRedirectUri());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package me.zhyd.oauth.authorization;
|
|
||||||
|
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 码云授权
|
|
||||||
*
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public class GiteeAuthorization implements Authorization {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAuthorizeUrl(AuthConfig config) {
|
|
||||||
return UrlBuilder.getGiteeAuthorizeUrl(config.getClientId(), config.getRedirectUri());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package me.zhyd.oauth.authorization;
|
|
||||||
|
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Github授权
|
|
||||||
*
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public class GithubAuthorization implements Authorization {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAuthorizeUrl(AuthConfig config) {
|
|
||||||
return UrlBuilder.getGithubAuthorizeUrl(config.getClientId(), config.getRedirectUri());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package me.zhyd.oauth.authorization;
|
|
||||||
|
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Google授权
|
|
||||||
*
|
|
||||||
* @author yangkai.shen (https://xkcoding.com)
|
|
||||||
* @version 1.3
|
|
||||||
* @since 1.3
|
|
||||||
*/
|
|
||||||
public class GoogleAuthorization implements Authorization {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAuthorizeUrl(AuthConfig config) {
|
|
||||||
return UrlBuilder.getGoogleAuthorizeUrl(config.getClientId(), config.getRedirectUri());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package me.zhyd.oauth.authorization;
|
|
||||||
|
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 开源中国授权
|
|
||||||
*
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public class OschinaAuthorization implements Authorization {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAuthorizeUrl(AuthConfig config) {
|
|
||||||
return UrlBuilder.getOschinaAuthorizeUrl(config.getClientId(), config.getRedirectUri());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package me.zhyd.oauth.authorization;
|
|
||||||
|
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* QQ授权
|
|
||||||
*
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public class QqAuthorization implements Authorization {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAuthorizeUrl(AuthConfig config) {
|
|
||||||
return UrlBuilder.getQqAuthorizeUrl(config.getClientId(), config.getRedirectUri());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package me.zhyd.oauth.authorization;
|
|
||||||
|
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 淘宝授权
|
|
||||||
*
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public class TaobaoAuthorization implements Authorization {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAuthorizeUrl(AuthConfig config) {
|
|
||||||
return UrlBuilder.getTaobaoAuthorizeUrl(config.getClientId(), config.getRedirectUri());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package me.zhyd.oauth.authorization;
|
|
||||||
|
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 腾讯云授权
|
|
||||||
*
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public class TencentCloudAuthorization implements Authorization {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAuthorizeUrl(AuthConfig config) {
|
|
||||||
return UrlBuilder.getTencentCloudAuthorizeUrl(config.getClientId(), config.getRedirectUri());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package me.zhyd.oauth.authorization;
|
|
||||||
|
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 微信授权
|
|
||||||
*
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public class WeChatAuthorization implements Authorization {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAuthorizeUrl(AuthConfig config) {
|
|
||||||
return UrlBuilder.getWeChatAuthorizeUrl(config.getClientId(), config.getRedirectUri());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package me.zhyd.oauth.authorization;
|
|
||||||
|
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 微博授权
|
|
||||||
*
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public class WeiboAuthorization implements Authorization {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAuthorizeUrl(AuthConfig config) {
|
|
||||||
return UrlBuilder.getWeiboAuthorizeUrl(config.getClientId(), config.getRedirectUri());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,8 +9,8 @@ import lombok.*;
|
|||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
@Setter
|
|
||||||
@Getter
|
@Getter
|
||||||
|
@Setter
|
||||||
@Builder
|
@Builder
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@@ -35,4 +35,27 @@ public class AuthConfig {
|
|||||||
* 支付宝公钥:当选择支付宝登录时,该值可用
|
* 支付宝公钥:当选择支付宝登录时,该值可用
|
||||||
*/
|
*/
|
||||||
private String alipayPublicKey;
|
private String alipayPublicKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否需要申请unionid,目前只针对qq登录
|
||||||
|
* 注:qq授权登录时,获取unionid需要单独发送邮件申请权限。如果个人开发者账号中申请了该权限,可以将该值置为true,在获取openId时就会同步获取unionId
|
||||||
|
* 参考链接:http://wiki.connect.qq.com/unionid%E4%BB%8B%E7%BB%8D
|
||||||
|
* <p>
|
||||||
|
* 1.7.1版本新增参数
|
||||||
|
*/
|
||||||
|
private boolean unionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一个神奇的参数,最好使用随机的不可测的内容,可以用来防止CSRF攻击
|
||||||
|
* <p>
|
||||||
|
* 1.8.0版本新增参数
|
||||||
|
*/
|
||||||
|
private String state;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stack Overflow Key
|
||||||
|
* <p>
|
||||||
|
* 1.9.0版本新增参数
|
||||||
|
*/
|
||||||
|
private String stackOverflowKey;
|
||||||
}
|
}
|
||||||
|
|||||||
+212
-134
@@ -1,7 +1,7 @@
|
|||||||
package me.zhyd.oauth.consts;
|
package me.zhyd.oauth.config;
|
||||||
|
|
||||||
import me.zhyd.oauth.exception.AuthException;
|
import me.zhyd.oauth.exception.AuthException;
|
||||||
import me.zhyd.oauth.request.ResponseStatus;
|
import me.zhyd.oauth.model.AuthResponseStatus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 各api需要的url, 用枚举类分平台类型管理
|
* 各api需要的url, 用枚举类分平台类型管理
|
||||||
@@ -10,7 +10,7 @@ import me.zhyd.oauth.request.ResponseStatus;
|
|||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
public enum ApiUrl {
|
public enum AuthSource {
|
||||||
/**
|
/**
|
||||||
* Github
|
* Github
|
||||||
*/
|
*/
|
||||||
@@ -29,16 +29,6 @@ public enum ApiUrl {
|
|||||||
public String userInfo() {
|
public String userInfo() {
|
||||||
return "https://api.github.com/user";
|
return "https://api.github.com/user";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String revoke() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String refresh() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 新浪微博
|
* 新浪微博
|
||||||
@@ -58,16 +48,6 @@ public enum ApiUrl {
|
|||||||
public String userInfo() {
|
public String userInfo() {
|
||||||
return "https://api.weibo.com/2/users/show.json";
|
return "https://api.weibo.com/2/users/show.json";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String revoke() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String refresh() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* gitee
|
* gitee
|
||||||
@@ -87,16 +67,6 @@ public enum ApiUrl {
|
|||||||
public String userInfo() {
|
public String userInfo() {
|
||||||
return "https://gitee.com/api/v5/user";
|
return "https://gitee.com/api/v5/user";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String revoke() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String refresh() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 钉钉
|
* 钉钉
|
||||||
@@ -109,23 +79,13 @@ public enum ApiUrl {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String accessToken() {
|
public String accessToken() {
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
throw new AuthException(AuthResponseStatus.UNSUPPORTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String userInfo() {
|
public String userInfo() {
|
||||||
return "https://oapi.dingtalk.com/sns/getuserinfo_bycode";
|
return "https://oapi.dingtalk.com/sns/getuserinfo_bycode";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String revoke() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String refresh() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 百度
|
* 百度
|
||||||
@@ -153,7 +113,7 @@ public enum ApiUrl {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String refresh() {
|
public String refresh() {
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
return "https://openapi.baidu.com/oauth/2.0/token";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@@ -174,16 +134,6 @@ public enum ApiUrl {
|
|||||||
public String userInfo() {
|
public String userInfo() {
|
||||||
return "https://api.csdn.net/user/getinfo";
|
return "https://api.csdn.net/user/getinfo";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String revoke() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String refresh() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Coding
|
* Coding
|
||||||
@@ -203,21 +153,11 @@ public enum ApiUrl {
|
|||||||
public String userInfo() {
|
public String userInfo() {
|
||||||
return "https://coding.net/api/account/current_user";
|
return "https://coding.net/api/account/current_user";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String revoke() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String refresh() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 腾讯云开发者平台(coding升级后就变成腾讯云开发者平台了)
|
* 腾讯云开发者平台(coding升级后就变成腾讯云开发者平台了)
|
||||||
*/
|
*/
|
||||||
TENCENTCLOUD {
|
TENCENT_CLOUD {
|
||||||
@Override
|
@Override
|
||||||
public String authorize() {
|
public String authorize() {
|
||||||
return "https://dev.tencent.com/oauth_authorize.html";
|
return "https://dev.tencent.com/oauth_authorize.html";
|
||||||
@@ -232,16 +172,6 @@ public enum ApiUrl {
|
|||||||
public String userInfo() {
|
public String userInfo() {
|
||||||
return "https://dev.tencent.com/api/account/current_user";
|
return "https://dev.tencent.com/api/account/current_user";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String revoke() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String refresh() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* oschina 开源中国
|
* oschina 开源中国
|
||||||
@@ -261,16 +191,6 @@ public enum ApiUrl {
|
|||||||
public String userInfo() {
|
public String userInfo() {
|
||||||
return "https://www.oschina.net/action/openapi/user";
|
return "https://www.oschina.net/action/openapi/user";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String revoke() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String refresh() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 支付宝
|
* 支付宝
|
||||||
@@ -290,16 +210,6 @@ public enum ApiUrl {
|
|||||||
public String userInfo() {
|
public String userInfo() {
|
||||||
return "https://openapi.alipay.com/gateway.do";
|
return "https://openapi.alipay.com/gateway.do";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String revoke() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String refresh() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* QQ
|
* QQ
|
||||||
@@ -320,14 +230,9 @@ public enum ApiUrl {
|
|||||||
return "https://graph.qq.com/user/get_user_info";
|
return "https://graph.qq.com/user/get_user_info";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String revoke() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String refresh() {
|
public String refresh() {
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
return "https://graph.qq.com/oauth2.0/token";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@@ -349,11 +254,6 @@ public enum ApiUrl {
|
|||||||
return "https://api.weixin.qq.com/sns/userinfo";
|
return "https://api.weixin.qq.com/sns/userinfo";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String revoke() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String refresh() {
|
public String refresh() {
|
||||||
return "https://api.weixin.qq.com/sns/oauth2/refresh_token";
|
return "https://api.weixin.qq.com/sns/oauth2/refresh_token";
|
||||||
@@ -375,17 +275,7 @@ public enum ApiUrl {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String userInfo() {
|
public String userInfo() {
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
throw new AuthException(AuthResponseStatus.UNSUPPORTED);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String revoke() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String refresh() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@@ -404,17 +294,7 @@ public enum ApiUrl {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String userInfo() {
|
public String userInfo() {
|
||||||
return "https://oauth2.googleapis.com/tokeninfo";
|
return "https://www.googleapis.com/oauth2/v3/userinfo";
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String revoke() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String refresh() {
|
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@@ -435,15 +315,209 @@ public enum ApiUrl {
|
|||||||
public String userInfo() {
|
public String userInfo() {
|
||||||
return "https://graph.facebook.com/v3.3/me";
|
return "https://graph.facebook.com/v3.3/me";
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 抖音
|
||||||
|
*/
|
||||||
|
DOUYIN {
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
return "https://open.douyin.com/platform/oauth/connect";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String revoke() {
|
public String accessToken() {
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
return "https://open.douyin.com/oauth/access_token/";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String userInfo() {
|
||||||
|
return "https://open.douyin.com/oauth/userinfo/";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String refresh() {
|
public String refresh() {
|
||||||
throw new AuthException(ResponseStatus.UNSUPPORTED);
|
return "https://open.douyin.com/oauth/refresh_token/";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 领英
|
||||||
|
*/
|
||||||
|
LINKEDIN {
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
return "https://www.linkedin.com/oauth/v2/authorization";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accessToken() {
|
||||||
|
return "https://www.linkedin.com/oauth/v2/accessToken";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String userInfo() {
|
||||||
|
return "https://api.linkedin.com/v2/me";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String refresh() {
|
||||||
|
return "https://www.linkedin.com/oauth/v2/accessToken";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 微软
|
||||||
|
*/
|
||||||
|
MICROSOFT {
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
return "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accessToken() {
|
||||||
|
return "https://login.microsoftonline.com/common/oauth2/v2.0/token";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String userInfo() {
|
||||||
|
return "https://graph.microsoft.com/v1.0/me";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String refresh() {
|
||||||
|
return "https://login.microsoftonline.com/common/oauth2/v2.0/token";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 小米
|
||||||
|
*/
|
||||||
|
MI {
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
return "https://account.xiaomi.com/oauth2/authorize";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accessToken() {
|
||||||
|
return "https://account.xiaomi.com/oauth2/token";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String userInfo() {
|
||||||
|
return "https://open.account.xiaomi.com/user/profile";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String refresh() {
|
||||||
|
return "https://account.xiaomi.com/oauth2/token";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 今日头条
|
||||||
|
*/
|
||||||
|
TOUTIAO {
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
return "https://open.snssdk.com/auth/authorize";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accessToken() {
|
||||||
|
return "https://open.snssdk.com/auth/token";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String userInfo() {
|
||||||
|
return "https://open.snssdk.com/data/user_profile";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Teambition
|
||||||
|
*/
|
||||||
|
TEAMBITION {
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
return "https://account.teambition.com/oauth2/authorize";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accessToken() {
|
||||||
|
return "https://account.teambition.com/oauth2/access_token";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String refresh() {
|
||||||
|
return "https://account.teambition.com/oauth2/refresh_token";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String userInfo() {
|
||||||
|
return "https://api.teambition.com/users/me";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人人网
|
||||||
|
*/
|
||||||
|
RENREN {
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
return "https://graph.renren.com/oauth/authorize";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accessToken() {
|
||||||
|
return "https://graph.renren.com/oauth/token";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String refresh() {
|
||||||
|
return "https://graph.renren.com/oauth/token";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String userInfo() {
|
||||||
|
return "https://api.renren.com/v2/user/get";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pinterest
|
||||||
|
*/
|
||||||
|
PINTEREST {
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
return "https://api.pinterest.com/oauth";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accessToken() {
|
||||||
|
return "https://api.pinterest.com/v1/oauth/token";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String userInfo() {
|
||||||
|
return "https://api.pinterest.com/v1/me";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stack Overflow
|
||||||
|
*/
|
||||||
|
STACK_OVERFLOW {
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
return "https://stackoverflow.com/oauth";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accessToken() {
|
||||||
|
return "https://stackoverflow.com/oauth/access_token/json";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String userInfo() {
|
||||||
|
return "https://api.stackexchange.com/2.2/me";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -473,13 +547,17 @@ public enum ApiUrl {
|
|||||||
*
|
*
|
||||||
* @return url
|
* @return url
|
||||||
*/
|
*/
|
||||||
public abstract String revoke();
|
public String revoke() {
|
||||||
|
throw new AuthException(AuthResponseStatus.UNSUPPORTED);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 刷新授权的api
|
* 刷新授权的api
|
||||||
*
|
*
|
||||||
* @return url
|
* @return url
|
||||||
*/
|
*/
|
||||||
public abstract String refresh();
|
public String refresh() {
|
||||||
|
throw new AuthException(AuthResponseStatus.UNSUPPORTED);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package me.zhyd.oauth.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 今日头条授权登录时的异常状态码
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.8
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum AuthToutiaoErrorCode {
|
||||||
|
EC0(0, "接口调用成功"),
|
||||||
|
EC1(1, "API配置错误,未传入Client Key"),
|
||||||
|
EC2(2, "API配置错误,Client Key错误,请检查是否和开放平台的ClientKey一致"),
|
||||||
|
EC3(3, "没有授权信息"),
|
||||||
|
EC4(4, "响应类型错误"),
|
||||||
|
EC5(5, "授权类型错误"),
|
||||||
|
EC6(6, "client_secret错误"),
|
||||||
|
EC7(7, "authorize_code过期"),
|
||||||
|
EC8(8, "指定url的scheme不是https"),
|
||||||
|
EC9(9, "接口内部错误,请联系头条技术"),
|
||||||
|
EC10(10, "access_token过期"),
|
||||||
|
EC11(11, "缺少access_token"),
|
||||||
|
EC12(12, "参数缺失"),
|
||||||
|
EC13(13, "url错误"),
|
||||||
|
EC21(21, "域名与登记域名不匹配"),
|
||||||
|
EC999(999, "未知错误,请联系头条技术"),
|
||||||
|
;
|
||||||
|
|
||||||
|
private int code;
|
||||||
|
private String desc;
|
||||||
|
|
||||||
|
public static AuthToutiaoErrorCode getErrorCode(int errorCode) {
|
||||||
|
AuthToutiaoErrorCode[] errorCodes = AuthToutiaoErrorCode.values();
|
||||||
|
for (AuthToutiaoErrorCode code : errorCodes) {
|
||||||
|
if (code.getCode() == errorCode) {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return EC999;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package me.zhyd.oauth.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
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, "未知");
|
||||||
|
private int code;
|
||||||
|
private String desc;
|
||||||
|
|
||||||
|
public static AuthUserGender getRealGender(String code) {
|
||||||
|
if (code == null) {
|
||||||
|
return UNKNOWN;
|
||||||
|
}
|
||||||
|
String[] males = {"m", "男", "1", "male"};
|
||||||
|
if (Arrays.asList(males).contains(code.toLowerCase())) {
|
||||||
|
return MALE;
|
||||||
|
}
|
||||||
|
String[] females = {"f", "女", "0", "female"};
|
||||||
|
if (Arrays.asList(females).contains(code.toLowerCase())) {
|
||||||
|
return FEMALE;
|
||||||
|
}
|
||||||
|
return UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package me.zhyd.oauth.exception;
|
package me.zhyd.oauth.exception;
|
||||||
|
|
||||||
import me.zhyd.oauth.request.ResponseStatus;
|
import me.zhyd.oauth.model.AuthResponseStatus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
@@ -13,16 +13,16 @@ public class AuthException extends RuntimeException {
|
|||||||
private String errorMsg;
|
private String errorMsg;
|
||||||
|
|
||||||
public AuthException(String errorMsg) {
|
public AuthException(String errorMsg) {
|
||||||
this(ResponseStatus.FAILURE.getCode(), errorMsg);
|
this(AuthResponseStatus.FAILURE.getCode(), errorMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AuthException(int errorCode, String errorMsg) {
|
public AuthException(int errorCode, String errorMsg) {
|
||||||
super(errorCode + ":" + errorMsg);
|
super(errorMsg);
|
||||||
this.errorCode = errorCode;
|
this.errorCode = errorCode;
|
||||||
this.errorMsg = errorMsg;
|
this.errorMsg = errorMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AuthException(ResponseStatus status) {
|
public AuthException(AuthResponseStatus status) {
|
||||||
super(status.getMsg());
|
super(status.getMsg());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,6 +30,10 @@ public class AuthException extends RuntimeException {
|
|||||||
super(message, cause);
|
super(message, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AuthException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
public int getErrorCode() {
|
public int getErrorCode() {
|
||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
package me.zhyd.oauth.model;
|
|
||||||
|
|
||||||
import me.zhyd.oauth.utils.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 百度授权登录时的异常状态码
|
|
||||||
*
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public enum AuthBaiduErrorCode {
|
|
||||||
OK("ok", "ok", "ok"),
|
|
||||||
INVALID_REQUEST("invalid_request", "invalid refresh token", "请求缺少某个必需参数,包含一个不支持的参数或参数值,或者格式不正确。"),
|
|
||||||
INVALID_CLIENT("invalid_client", "unknown client id", "client_id”、“client_secret”参数无效。"),
|
|
||||||
INVALID_GRANT("invalid_grant", "The provided authorization grant is revoked", "提供的Access Grant是无效的、过期的或已撤销的,例如,Authorization Code无效(一个授权码只能使用一次)、Refresh Token无效、redirect_uri与获取Authorization Code时提供的不一致、Devie Code无效(一个设备授权码只能使用一次)等。"),
|
|
||||||
UNAUTHORIZED_CLIENT("unauthorized_client", "The client is not authorized to use this authorization grant type", "应用没有被授权,无法使用所指定的grant_type。"),
|
|
||||||
UNSUPPORTED_GRANT_TYPE("unsupported_grant_type", "The authorization grant type is not supported", "“grant_type”百度OAuth2.0服务不支持该参数。"),
|
|
||||||
INVALID_SCOPE("invalid_scope", "The requested scope is exceeds the scope granted by the resource owner", "请求的“scope”参数是无效的、未知的、格式不正确的、或所请求的权限范围超过了数据拥有者所授予的权限范围。"),
|
|
||||||
EXPIRED_TOKEN("expired_token", "refresh token has been used", "提供的Refresh Token已过期"),
|
|
||||||
REDIRECT_URI_MISMATCH("redirect_uri_mismatch", "Invalid redirect uri", "“redirect_uri”所在的根域与开发者注册应用时所填写的根域名不匹配。"),
|
|
||||||
UNSUPPORTED_RESPONSE_TYPE("unsupported_response_type", "The response type is not supported", "“response_type”参数值不为百度OAuth2.0服务所支持,或者应用已经主动禁用了对应的授权模式"),
|
|
||||||
SLOW_DOWN("slow_down", "The device is polling too frequently", "Device Flow中,设备通过Device Code换取Access Token的接口过于频繁,两次尝试的间隔应大于5秒。"),
|
|
||||||
AUTHORIZATION_PENDING("authorization_pending", "User has not yet completed the authorization", "Device Flow中,用户还没有对Device Code完成授权操作。"),
|
|
||||||
AUTHORIZATION_DECLINED("authorization_declined", "User has declined the authorization", "Device Flow中,用户拒绝了对Device Code的授权操作。"),
|
|
||||||
INVALID_REFERER("invalid_referer", "Invalid Referer", "Implicit Grant模式中,浏览器请求的Referer与根域名绑定不匹配");
|
|
||||||
|
|
||||||
private String code;
|
|
||||||
private String msg;
|
|
||||||
private String desc;
|
|
||||||
|
|
||||||
AuthBaiduErrorCode(String code, String msg, String desc) {
|
|
||||||
this.code = code;
|
|
||||||
this.msg = msg;
|
|
||||||
this.desc = desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AuthBaiduErrorCode getErrorCode(String code) {
|
|
||||||
if (StringUtils.isEmpty(code)) {
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
AuthBaiduErrorCode[] errorCodes = AuthBaiduErrorCode.values();
|
|
||||||
for (AuthBaiduErrorCode errorCode : errorCodes) {
|
|
||||||
if (code.equalsIgnoreCase(errorCode.getCode())) {
|
|
||||||
return errorCode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCode() {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMsg() {
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDesc() {
|
|
||||||
return desc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package me.zhyd.oauth.model;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 授权回调时的参数类
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.8
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class AuthCallback {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问AuthorizeUrl后回调时带的参数code
|
||||||
|
*/
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问AuthorizeUrl后回调时带的参数auth_code,该参数目前只使用于支付宝登录
|
||||||
|
*/
|
||||||
|
private String auth_code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问AuthorizeUrl后回调时带的参数state,用于和请求AuthorizeUrl前的state比较,防止CSRF攻击
|
||||||
|
*/
|
||||||
|
private String state;
|
||||||
|
}
|
||||||
@@ -1,404 +0,0 @@
|
|||||||
package me.zhyd.oauth.model;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 钉钉授权登录时的异常状态码
|
|
||||||
*
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public enum AuthDingTalkErrorCode {
|
|
||||||
EC1_MINUS(-1, "系统繁忙", "服务器暂不可用,建议稍候再重试1次,最多重试3次"),
|
|
||||||
EC0(0, "请求成功", "接口调用成功"),
|
|
||||||
EC404(404, "请求的URI地址不存在", "地址不存在,检查下url是否和文档里写的一致"),
|
|
||||||
EC33001(33001, "无效的企业ID", "请确认下access_token是否正确"),
|
|
||||||
EC33002(33002, "无效的微应用的名称", "校验下微应用的名称字段,不能为空且长度不能超过10个字符"),
|
|
||||||
EC33003(33003, "无效的微应用的描述", "校验下微应用的描述字段,不能为空且长度不能超过20个字符"),
|
|
||||||
EC33004(33004, "无效的微应用的ICON", "校验下微应用的icon字段,不能为空且确保图标存在"),
|
|
||||||
EC33005(33005, "无效的微应用的移动端主页", "校验下微应用的移动端主页,不能为空且必须以http开头或https开头"),
|
|
||||||
EC33006(33006, "无效的微应用的PC端主页", "校验下微应用的PC端主页,必须以http开头或https开头"),
|
|
||||||
EC33007(33007, "微应用的移动端的主页与PC端主页不同", "校验下微应用的PC端主页,确保它和移动端主页的域名保持一致"),
|
|
||||||
EC33008(33008, "无效的微应用OA后台的主页", "校验下微应用的后台管理的主页失败,必须以http开头或https开头"),
|
|
||||||
EC34001(34001, "无效的会话id", "检查下所传的chatId字段是否为空"),
|
|
||||||
EC34002(34002, "无效的会话消息的发送者", "检查下sender字段是否为空"),
|
|
||||||
EC34003(34003, "无效的会话消息的发送者的企业Id", "检查下发送者的企业Id"),
|
|
||||||
EC34004(34004, "无效的会话消息的类型", "检查下msgtype字段,是否为空,是否是定义的那几种类型"),
|
|
||||||
EC34005(34005, "无效的会话音频消息的播放时间", "该错误码已废弃"),
|
|
||||||
EC34006(34006, "发送者不在企业中", "检查下发送者是否在企业中"),
|
|
||||||
EC34007(34007, "发送者不在会话中", "检查下发送者是否在会话id中"),
|
|
||||||
EC34008(34008, "图片不能为空", "如果发的是图片消息,检查下图片是否为空"),
|
|
||||||
EC34009(34009, "链接内容不能为空", "检查下messageUrl字段是否为空"),
|
|
||||||
EC34010(34010, "文件不能为空", "检查下media_id字段是否为空"),
|
|
||||||
EC34011(34011, "音频文件不能为空", "检查下media_id字段是否为空"),
|
|
||||||
EC34012(34012, "找不到发送者的企业", "检查下发送者是否是真实的"),
|
|
||||||
EC34013(34013, "找不到群会话对象", "检查下chatid是否真实存在"),
|
|
||||||
EC34014(34014, "会话消息的json结构无效或不完整", "检查下消息的json格式是否正确,json的key对应msgtype的value值"),
|
|
||||||
EC34015(34015, "发送群会话消息失败", "消息发送失败,建议稍后再重试下"),
|
|
||||||
EC34016(34016, "消息内容长度超过限制", "检查下消息的content字段长度是否超过5000,title字段长度是否超过64,markdown字段长度是否超过5000,single_title字段长度是否超过20,single_url字段长度是否超过500,btn_json_list字段长度是否超过1000"),
|
|
||||||
EC40001(40001, "获取access_token时Secret错误,或者access_token无效", "检查下access_token是否正确"),
|
|
||||||
EC40002(40002, "不合法的凭证类型", "无"),
|
|
||||||
EC40003(40003, "不合法的UserID", "确保该id在通讯录中存在,且是在你所传access_token对应的企业里"),
|
|
||||||
EC40004(40004, "不合法的媒体文件类型", "检查下type字段,只支持image,voice,file"),
|
|
||||||
EC40005(40005, "不合法的文件类型", "如果是文件类型,检查下是否是支持的那几种,目前只支持doc,docx,xls,xlsx,ppt,pptx,zip,pdf,rar"),
|
|
||||||
EC40006(40006, "不合法的文件大小", "检查下文件大小,image类型最大1MB,file类型最大10MB,voice类型最大2MB"),
|
|
||||||
EC40007(40007, "不合法的媒体文件id", "检查下mediaId是否为空,是否真实存在"),
|
|
||||||
EC40008(40008, "不合法的消息类型", "检查下msgtype是否为空,确保它在开放平台定义的几种类型里,具体见消息类型及格式"),
|
|
||||||
EC40009(40009, "不合法的部门id", "检查下部门id是否为空,是否为数字且大于0"),
|
|
||||||
EC40010(40010, "不合法的父部门id", "检查下父部门id是否为一个数字"),
|
|
||||||
EC40011(40011, "不合法的排序order", "检查下order字段是否为空,是否为数字且大于0"),
|
|
||||||
EC40012(40012, "不合法的发送者", "检查下sender字段是否为空,是否真实存在"),
|
|
||||||
EC40013(40013, "不合法的corpid", "检查下corpid是否有效"),
|
|
||||||
EC40014(40014, "不合法的access_token", "检查下access_token是否正确,注意access_token这个参数应该是带在url后面的"),
|
|
||||||
EC40015(40015, "发送者不在会话中", "检查下sender字段和cid字段是否能对应上"),
|
|
||||||
EC40016(40016, "不合法的会话ID", "检查下cid字段是否为空,是否有效"),
|
|
||||||
EC40017(40017, "在会话中没有找到与发送者在同一企业的人", "cid对应的消息接收者为空,检查下cid字段"),
|
|
||||||
EC40018(40018, "不允许以递归方式查询部门用户列表", "检查下fetchChild字段,目前不支持递归查询"),
|
|
||||||
EC40019(40019, "该手机号码对应的用户最多可以加入5个非认证企业", "无"),
|
|
||||||
EC40020(40020, "当前团队人数已经达到上限,用电脑登录钉钉企业管理后台,升级成为认证企业", "无"),
|
|
||||||
EC40021(40021, "更换的号码已注册过钉钉,无法使用该号码", "无"),
|
|
||||||
EC40022(40022, "企业中的手机号码和登录钉钉的手机号码不一致,暂时不支持修改用户信息,可以删除后重新添加", "无"),
|
|
||||||
EC40023(40023, "部门人数达到上限", "部门人数不能超过1000"),
|
|
||||||
EC40024(40024, "(安全校验不通过)保存失败,团队人数超限。请在手机钉钉绑定支付宝完成实名认证,或者申请企业认证,人数上限自动扩充", "无"),
|
|
||||||
EC40025(40025, "无效的部门JSONArray对象,合法格式需要用中括号括起来,且如果属于多部门,部门id需要用逗号分隔", "无"),
|
|
||||||
EC40029(40029, "不合法的oauth_code", "无"),
|
|
||||||
EC40031(40031, "不合法的UserID列表", "指定的UserID列表,至少存在一个UserID不在通讯录中"),
|
|
||||||
EC40032(40032, "不合法的UserID列表长度", "检查下列表是否为空,且长度合适。创建部门接口的userPerimits最多接收10000个"),
|
|
||||||
EC40033(40033, "不合法的请求字符,不能包含\\uxxxx格式的字符", "无"),
|
|
||||||
EC40035(40035, "不合法的参数", "检查下有没有传请求参数,一般发生在http post形式的接口里,没有传参数"),
|
|
||||||
EC40038(40038, "不合法的请求格式", "检查下参数中是不是少了某个字段,具体参考各个文档的参数介绍"),
|
|
||||||
EC40039(40039, "不合法的URL长度", "无"),
|
|
||||||
EC40048(40048, "url中包含不合法domain", "发消息接口中消息url链接不安全"),
|
|
||||||
EC40055(40055, "不合法的agent结构", "已废弃"),
|
|
||||||
EC40056(40056, "不合法的agentid", "检查下agentid字段是否为空,是否真实存在"),
|
|
||||||
EC40057(40057, "不合法的callbackurl", "无"),
|
|
||||||
EC40061(40061, "设置应用头像失败", "无"),
|
|
||||||
EC40062(40062, "不合法的应用模式", "无"),
|
|
||||||
EC40063(40063, "不合法的分机号", "tel字段长度超长,长度不能超过50"),
|
|
||||||
EC40064(40064, "不合法的工作地址", "workPlace长度超长,长度不能超过50个字符"),
|
|
||||||
EC40065(40065, "不合法的备注", "remark长度超长,长度不能超过1024个字符"),
|
|
||||||
EC40066(40066, "不合法的部门列表", "部门id列表长度太长,不能超过10000,并且每个id必须是数字"),
|
|
||||||
EC40067(40067, "标题长度不合法", "检查下标题长度"),
|
|
||||||
EC40068(40068, "不合法的偏移量", "偏移量必须大于0"),
|
|
||||||
EC40069(40069, "不合法的分页大小", "分页大小不合法,具体参考每个接口的参数定义"),
|
|
||||||
EC40070(40070, "不合法的排序参数", "具体参考获取部门成员接口里面对order字段的定义"),
|
|
||||||
EC40073(40073, "不存在的openid", "openid不能为空"),
|
|
||||||
EC40077(40077, "不存在的预授权码", "无"),
|
|
||||||
EC40078(40078, "不存在的临时授权码", "临时授权码不能为空,且只能被使用一次"),
|
|
||||||
EC40079(40079, "不存在的授权信息", "检查下企业是否授权"),
|
|
||||||
EC40080(40080, "不合法的suitesecret", "无"),
|
|
||||||
EC40082(40082, "不合法的suitetoken", "检查下token"),
|
|
||||||
EC40083(40083, "不合法的suiteid", "suiteKey字段不合法"),
|
|
||||||
EC40084(40084, "不合法的永久授权码", "检查下永久授权码是否正确"),
|
|
||||||
EC40085(40085, "不存在的suiteticket", "检查下suiteticket是否正确,确保是由回调接口正确来接收suiteticket"),
|
|
||||||
EC40086(40086, "不合法的第三方应用appid", "appid字段不能为空"),
|
|
||||||
EC40087(40087, "创建永久授权码失败", "稍后再重试下,确保参数都传对"),
|
|
||||||
EC40088(40088, "不合法的套件key或secret", "稍后再重试下,确保suiteKey和suiteSecret都传对且一一对应"),
|
|
||||||
EC40089(40089, "不合法的corpid或corpsecret", "稍后再重试下,确保corpid和corpsecret字段传对且一一对应"),
|
|
||||||
EC40090(40090, "套件已经不存在", "检查下suiteKey字段是否正确"),
|
|
||||||
EC40091(40091, "用户授权码创建失败,需要用户重新授权", "创建永久授权码失败,需要用户重新授权产生临时授权码"),
|
|
||||||
EC40103(40103, "用户开启了账号保护,无法被加入到您的团队", "用户在钉钉“我的-设置-隐私”出开启了账号保护"),
|
|
||||||
EC40104(40104, "无效手机号", "检查手机号格式是否正确"),
|
|
||||||
EC41001(41001, "缺少access_token参数", "检查下access_token是否传了,注意该参数必须跟在请求url中"),
|
|
||||||
EC41002(41002, "缺少corpid参数", "检查下corpid是否为空"),
|
|
||||||
EC41003(41003, "缺少refresh_token参数", "检查下refresh_token是否为空"),
|
|
||||||
EC41004(41004, "缺少secret参数", "检查下secret参数是否为空"),
|
|
||||||
EC41005(41005, "缺少多媒体文件数据", "无"),
|
|
||||||
EC41006(41006, "缺少media_id参数", "检查下media_id参数是否为空"),
|
|
||||||
EC41007(41007, "无效的ssocode", "sso的永久授权code无效,检查下是否为空"),
|
|
||||||
EC41008(41008, "缺少oauth", "无"),
|
|
||||||
EC41009(41009, "缺少UserID", "检查下UserID是否为空"),
|
|
||||||
EC41010(41010, "缺少url", "检查下url是否为空"),
|
|
||||||
EC41011(41011, "缺少agentid", "检查下agentid是否为空"),
|
|
||||||
EC41012(41012, "缺少应用头像mediaid", "检查下mediaid是否为空"),
|
|
||||||
EC41013(41013, "缺少应用名字", "检查应用名字是否为空"),
|
|
||||||
EC41014(41014, "缺少应用描述", "检查应用描述是否为空"),
|
|
||||||
EC41015(41015, "缺少JSON参数", "检查JSON参数是否为空"),
|
|
||||||
EC41021(41021, "缺少suitekey", "检查suitekey参数是否为空"),
|
|
||||||
EC41022(41022, "缺少suitetoken", "检查suitetoken参数是否为空"),
|
|
||||||
EC41023(41023, "缺少suiteticket", "检查suiteticket参数是否为空"),
|
|
||||||
EC41024(41024, "缺少suitesecret", "检查suitesecret参数是否为空"),
|
|
||||||
EC41025(41025, "缺少permanent_code", "检查permanent_code永久授权码参数是否为空"),
|
|
||||||
EC41026(41026, "缺少tmp_auth_code", "检查tmp_auth_code临时授权码参数是否为空"),
|
|
||||||
EC41027(41027, "需要授权企业的corpid参数", "检查corpid参数是否为空"),
|
|
||||||
EC41028(41028, "禁止给全员发送消息", "检查是否有全员发送消息的权限,ISV没有该权限"),
|
|
||||||
EC41029(41029, "超过消息接收者人数上限", "发送OA消息人数超上限(企业消息人数上限:5000,ISV消息人数上限:1000)"),
|
|
||||||
EC41030(41030, "企业未对该套件授权", "检查该企业是否已经对该套件进行授权"),
|
|
||||||
EC41031(41031, "auth_corpid和permanent_code不匹配", "激活套件时使用的auth_corpid和permanent_code不匹配"),
|
|
||||||
EC41041(41041, "查询间隔时间太长", "考勤打卡数据查询间隔时间超过7天"),
|
|
||||||
EC41044(41044, "禁止发送消息", "检查是否有权限发送消息"),
|
|
||||||
EC41045(41045, "单应用全员消息/每天总量超限", "无"),
|
|
||||||
EC41046(41046, "超过发送全员消息的每分钟次数上限", "企业OA消息全员发送每天不能超过3次,ISV不能发送全员消息"),
|
|
||||||
EC41047(41047, "超过给该企业发消息的每分钟次数上限", "企业OA消息每分钟不能超过1500次,ISV OA消息每分钟不能超过200次"),
|
|
||||||
EC41048(41048, "超过给企业发消息的每分钟次数总上限", ""),
|
|
||||||
EC41049(41049, "包含违禁内容", "检查消息文本中是否有黄色、反动等词语"),
|
|
||||||
EC41050(41050, "无效的活动编码", "无"),
|
|
||||||
EC41051(41051, "活动权益的校验失败", "无"),
|
|
||||||
EC41100(41100, "时间参数不合法", "时间参数不能为空,且为“yyyy-MM-dd hh:mm:ss”格式"),
|
|
||||||
EC41101(41101, "数据内容过长", "请求体字符长度不能大于4096"),
|
|
||||||
EC41102(41102, "参数值过大", "上传文件或者idlist等参数过大"),
|
|
||||||
EC42001(42001, "access_token超时", "请检查网络状态"),
|
|
||||||
EC42002(42002, "refresh_token超时", "请检查网络状态"),
|
|
||||||
EC42003(42003, "oauth_code超时", "请检查网络状态"),
|
|
||||||
EC42007(42007, "预授权码失效", "请检查该预授权码是否已经使用过"),
|
|
||||||
EC42008(42008, "临时授权码失效", "请检查该临时授权码是否已经使用过或者是否不正确"),
|
|
||||||
EC42009(42009, "suitetoken失效", "请检查该suitetoken是否已经过期"),
|
|
||||||
EC43001(43001, "需要GET请求", "请检查http请求方式是否正确"),
|
|
||||||
EC43002(43002, "需要POST请求", "请检查http请求方式是否正确"),
|
|
||||||
EC43003(43003, "需要HTTPS", "请检查调用接口协议是否是https"),
|
|
||||||
EC43004(43004, "无效的HTTP HEADER Content-Type", "请检查请求头中的content-type是否正确"),
|
|
||||||
EC43005(43005, "需要Content-Type为application/json;charset=UTF-8", "请检查请求头中的content-type是否是“application/json;charset=UTF-8”"),
|
|
||||||
EC43007(43007, "需要授权", "该接口需要access_token才能调用"),
|
|
||||||
EC43008(43008, "参数需要multipart类型", "检查提交参数中的ENCTYPE是否是multipart类型"),
|
|
||||||
EC43009(43009, "post参数需要json类型", "请检查post参数数据是否是json类型"),
|
|
||||||
EC44001(44001, "多媒体文件为空", "请检查多媒体文件数据是否为空"),
|
|
||||||
EC44002(44002, "POST的数据包为空", "请检查POST的数据包是否为空"),
|
|
||||||
EC44003(44003, "图文消息内容为空", "请检查图文消息参数是否为空"),
|
|
||||||
EC44004(44004, "文本消息内容为空", "请检查文本消息参数是否为空"),
|
|
||||||
EC45001(45001, "多媒体文件大小超过限制", "无"),
|
|
||||||
EC45002(45002, "消息内容超过限制", "无"),
|
|
||||||
EC45003(45003, "标题字段超过限制", "无"),
|
|
||||||
EC45004(45004, "描述字段超过限制", "无"),
|
|
||||||
EC45005(45005, "链接字段超过限制", "无"),
|
|
||||||
EC45006(45006, "图片链接字段超过限制", "无"),
|
|
||||||
EC45007(45007, "语音播放时间超过限制", "无"),
|
|
||||||
EC45008(45008, "图文消息超过限制", "无"),
|
|
||||||
EC45009(45009, "接口调用超过限制", "无"),
|
|
||||||
EC45016(45016, "系统分组,不允许修改", "无"),
|
|
||||||
EC45017(45017, "分组名字过长", "无"),
|
|
||||||
EC45018(45018, "分组数量超过上限", "无"),
|
|
||||||
EC45024(45024, "账号数量超过上限", "无"),
|
|
||||||
EC46001(46001, "不存在媒体数据", "无"),
|
|
||||||
EC46004(46004, "不存在的员工", "无"),
|
|
||||||
EC47001(47001, "解析JSON/XML内容错误", "无"),
|
|
||||||
EC48002(48002, "Api禁用", "无"),
|
|
||||||
EC48003(48003, "suitetoken无效", "无"),
|
|
||||||
EC48004(48004, "授权关系无效", "无"),
|
|
||||||
EC49000(49000, "缺少chatid", "请检查参数中是否有chatid"),
|
|
||||||
EC49001(49001, "绑定的微应用超过个数限制", "绑定群会话和微应用超过5个"),
|
|
||||||
EC49002(49002, "一个群只能被一个ISV套件绑定一次", "无"),
|
|
||||||
EC49003(49003, "操作者必须为群主", "无"),
|
|
||||||
EC49004(49004, "添加成员列表和删除成员列表不能有交集", "无"),
|
|
||||||
EC49005(49005, "群人数超过人数限制", "无"),
|
|
||||||
EC49006(49006, "群成员列表必须包含群主", "无"),
|
|
||||||
EC49007(49007, "超过创建群的个数上限", "无"),
|
|
||||||
EC49008(49008, "不合法的群类型,只能传入0或2", "无"),
|
|
||||||
EC49009(49009, "企业群不能添加外部联系人,群主只能为企业员工", "无"),
|
|
||||||
EC49010(49010, "群成员不能为空", "无"),
|
|
||||||
EC49011(49011, "群员工列表超长", "无"),
|
|
||||||
EC49012(49012, "群外部联系人列表超长", "无"),
|
|
||||||
EC49013(49013, "群主不能为空", "无"),
|
|
||||||
EC49014(49014, "非法的群主类型,只能为emp或者ext", "无"),
|
|
||||||
EC49015(49015, "不合法的群名称", "无"),
|
|
||||||
EC49016(49016, "查询企业员工不存在", "无"),
|
|
||||||
EC49017(49017, "查询企业外部联系人不存在", "无"),
|
|
||||||
EC49018(49018, "群主非企业员工", "无"),
|
|
||||||
EC49019(49019, "群主非企业外部通讯录人员", "无"),
|
|
||||||
EC49020(49020, "某人处于勿扰模式,拒绝加入群聊;请先与TA建立好友关系", "无"),
|
|
||||||
EC49021(49021, "非好友建立群聊,认证用户一天只能拉50个人,非认证用户一天只能拉10个人", "无"),
|
|
||||||
EC49022(49022, "某人拒绝加入群聊", "无"),
|
|
||||||
EC49023(49023, "某人处于勿扰模式,拒绝加入群聊;请先与TA建立好友关系", "无"),
|
|
||||||
EC50001(50001, "redirect_uri未授权", "无"),
|
|
||||||
EC50002(50002, "员工不在权限范围", "无"),
|
|
||||||
EC50003(50003, "应用已停用", "无"),
|
|
||||||
EC50004(50004, "企业部门不在授权范围", "检查企业部门是否设置可见范围,具体排查方法请参考通讯录FAQ"),
|
|
||||||
EC50005(50005, "企业已禁用", "无"),
|
|
||||||
EC52010(52010, "无效的corpid", "请检查corpid参数是否正确"),
|
|
||||||
EC52011(52011, "jsapi ticket 读取失败", "请检查ticket参数是否正确"),
|
|
||||||
EC52012(52012, "jsapi 签名生成失败", "请检查“url, nonceStr, timestamp, ticket”等参数是否正确"),
|
|
||||||
EC52013(52013, "签名校验失败", "请检查“url, nonceStr, timestamp, ticket”等参数是否正确"),
|
|
||||||
EC52014(52014, "无效的url参数", "请检查url参数是否正确"),
|
|
||||||
EC52015(52015, "无效的随机字符串参数", "请检查nonceStr参数是否正确"),
|
|
||||||
EC52016(52016, "无效的签名参数", "请检查“url, nonceStr, timestamp, ticket”等参数是否正确"),
|
|
||||||
EC52017(52017, "无效的jsapi列表参数", "请检查dd.config中的jsApiList参数是否正确"),
|
|
||||||
EC52018(52018, "无效的时间戳", "请检查timestamp参数是否正确"),
|
|
||||||
EC52019(52019, "无效的agentid", "请检查agentid参数是否正确"),
|
|
||||||
EC60001(60001, "不合法的部门名称", "请检查部门名称是否正确,长度不能超过64个字符"),
|
|
||||||
EC60002(60002, "部门层级深度超过限制", "无"),
|
|
||||||
EC60003(60003, "部门不存在", "无"),
|
|
||||||
EC60004(60004, "父亲部门不存在", "无"),
|
|
||||||
EC60005(60005, "不允许删除有成员的部门", "无"),
|
|
||||||
EC60006(60006, "不允许删除有子部门的部门", "无"),
|
|
||||||
EC60007(60007, "不允许删除根部门", "无"),
|
|
||||||
EC60008(60008, "父部门下该部门名称已存在", "无"),
|
|
||||||
EC60009(60009, "部门名称含有非法字符", "无"),
|
|
||||||
EC60010(60010, "部门存在循环关系", "无"),
|
|
||||||
EC60011(60011, "没有调用该接口的权限", "请检查当前请求使用的access_token是否有对该部门/人的操作权限,查看获取appSecret授权范围"),
|
|
||||||
EC60012(60012, "不允许删除默认应用", "无"),
|
|
||||||
EC60013(60013, "不允许关闭应用", "无"),
|
|
||||||
EC60014(60014, "不允许开启应用", "无"),
|
|
||||||
EC60015(60015, "不允许修改默认应用可见范围", "无"),
|
|
||||||
EC60016(60016, "部门id已经存在", "无"),
|
|
||||||
EC60017(60017, "不允许设置企业", "无"),
|
|
||||||
EC60018(60018, "不允许更新根部门", "无"),
|
|
||||||
EC60019(60019, "从部门查询人员失败", "请检查该成员是否在该部门中"),
|
|
||||||
EC60020(60020, "访问ip不在白名单之中", "如果是企业应用,检查配置的服务器出口ip地址是否和请求ip地址一致。如果是isv应用,请检查套件ip白名单和请求ip是否一致"),
|
|
||||||
EC60067(60067, "部门的企业群群主不存在", "无"),
|
|
||||||
EC60068(60068, "部门的管理员不存在", "无"),
|
|
||||||
EC60102(60102, "UserID在公司中已存在", "无"),
|
|
||||||
EC60103(60103, "手机号码不合法", "无"),
|
|
||||||
EC60104(60104, "手机号码在公司中已存在", "无"),
|
|
||||||
EC60105(60105, "邮箱不合法", "无"),
|
|
||||||
EC60106(60106, "邮箱已存在", "无"),
|
|
||||||
EC60107(60107, "使用该手机登录钉钉的用户已经在企业中", "无"),
|
|
||||||
EC60110(60110, "部门个数超出限制", "无"),
|
|
||||||
EC60111(60111, "UserID不存在", "无"),
|
|
||||||
EC60112(60112, "用户name不合法", "无"),
|
|
||||||
EC60113(60113, "身份认证信息(手机/邮箱)不能同时为空", "无"),
|
|
||||||
EC60114(60114, "性别不合法", "无"),
|
|
||||||
EC60118(60118, "用户无有效邀请字段(邮箱,手机号)", "无"),
|
|
||||||
EC60119(60119, "不合法的position", "无"),
|
|
||||||
EC60120(60120, "用户已禁用", "无"),
|
|
||||||
EC60121(60121, "找不到该用户", "检查该企业下该员工是否存在"),
|
|
||||||
EC60122(60122, "不合法的extattr", "无"),
|
|
||||||
EC60123(60123, "不合法的jobnumber", "无"),
|
|
||||||
EC60124(60124, "用户不在此群中", "无"),
|
|
||||||
EC60125(60125, "CRM配置信息创建失败", "无"),
|
|
||||||
EC60126(60126, "CRM配置信息更新失败", "无"),
|
|
||||||
EC60127(60127, "CRM人员配置信息删除失败", "无"),
|
|
||||||
EC70001(70001, "企业不存在或者已经被解散", "无"),
|
|
||||||
EC70002(70002, "获取套件下的微应用失败", "无"),
|
|
||||||
EC70003(70003, "agentid对应微应用不存在", "无"),
|
|
||||||
EC70004(70004, "企业下没有对应该agentid的微应用", "注意:代表应用和企业映射关系的ID (appId的实例化ID),同一个ISV应用在不同企业的agentId不一致"),
|
|
||||||
EC70005(70005, "ISV激活套件失败", "请检查激活套件使用的参数是否正确"),
|
|
||||||
EC71006(71006, "回调地址已经存在", "无"),
|
|
||||||
EC71007(71007, "回调地址已不存在", "无"),
|
|
||||||
EC71008(71008, "回调call_back_tag必须在指定的call_back_tag列表中", "无"),
|
|
||||||
EC71009(71009, "返回文本非success", "回调地址返回的内容必须是“success”文本经过加密后的结果"),
|
|
||||||
EC71010(71010, "POST的JSON数据不包含所需要的参数字段或包含的参数格式非法", "无"),
|
|
||||||
EC71011(71011, "传入的url参数不是合法的url格式", "合法的URL地址是协议+域名+端口+路径path+参数组成"),
|
|
||||||
EC71012(71012, "url地址访问异常", "无"),
|
|
||||||
EC71013(71013, "此域名或IP不能注册或者接收回调事件", "注意回调地址的域名或者IP必须在套件的ip白名单中,并且该ip必须为外网ip"),
|
|
||||||
EC72001(72001, "获取钉盘空间失败", "检查domain、agent_id、access_token参数是否正确有效"),
|
|
||||||
EC72002(72002, "授权钉盘空间访问权限失败", "无"),
|
|
||||||
EC80001(80001, "可信域名没有IPC备案,后续将不能在该域名下正常使用jssdk", "无"),
|
|
||||||
EC81001(81001, "两个用户没有任何关系,请先相互成为好友", "无"),
|
|
||||||
EC81002(81002, "用户拒收消息", "无"),
|
|
||||||
EC88005(88005, "管理日历个人日历操作失败", "无"),
|
|
||||||
EC89001(89001, "管理日历启动导出任务失败", "无"),
|
|
||||||
EC89011(89011, "管理日历写入数据失败", "无"),
|
|
||||||
EC89012(89012, "管理日历更新数据失败", "无"),
|
|
||||||
EC90001(90001, "您的服务器调用钉钉开放平台所有接口的请求都被暂时禁用了", "无"),
|
|
||||||
EC90002(90002, "您的服务器调用钉钉开放平台当前接口的所有请求都被暂时禁用了", "无"),
|
|
||||||
EC90003(90003, "您的企业调用钉钉开放平台所有接口的请求都被暂时禁用了,仅对企业自己的Accesstoken有效", "无"),
|
|
||||||
EC90004(90004, "您当前使用的CorpId及CorpSecret被暂时禁用了,仅对企业自己的Accesstoken有效", "无"),
|
|
||||||
EC90005(90005, "您的企业调用当前接口次数过多,请求被暂时禁用了,仅对企业自己的Accesstoken有效", "无"),
|
|
||||||
EC90006(90006, "您当前使用的CorpId及CorpSecret调用当前接口次数过多,请求被暂时禁用了,仅对企业自己的Accesstoken有效", "无"),
|
|
||||||
EC90007(90007, "您当前要调用的企业的接口次数过多,对该企业的所有请求都被暂时禁用了,仅对企业授权给ISV的Accesstoken有效", "无"),
|
|
||||||
EC90008(90008, "您当前要调用的企业的当前接口次数过多,对此企业下该接口的所有请求都被暂时禁用了,仅对企业授权给ISV的Accesstoken有效", "无"),
|
|
||||||
EC90009(90009, "您调用企业接口超过了限制,对所有企业的所有接口的请求都被暂时禁用了,仅对企业授权给ISV的Accesstoken有效", "无"),
|
|
||||||
EC90010(90010, "您调用企业当前接口超过了限制,对所有企业的该接口的请求都被暂时禁用了,仅对企业授权给ISV的Accesstoken有效", "无"),
|
|
||||||
EC90011(90011, "您的套件调用企业接口超过了限制,该套件的所有请求都被暂时禁用了,仅对企业授权给ISV的Accesstoken有效", "无"),
|
|
||||||
EC90012(90012, "您的套件调用企业当前接口超过了限制,该套件对此接口的所有请求都被暂时禁用了,仅对企业授权给ISV的Accesstoken有效", "无"),
|
|
||||||
EC90013(90013, "您的套件调用当前企业的接口超过了限制,该套件对此企业的所有请求都被暂时禁用了,仅对企业授权给ISV的Accesstoken有效", "无"),
|
|
||||||
EC90014(90014, "您的套件调用企业当前接口超过了限制,该套件对此企业该接口的所有请求都被暂时禁用了,仅对企业授权给ISV的Accesstoken有效", "无"),
|
|
||||||
EC900001(900001, "加密明文文本非法", "加密明文不能为空"),
|
|
||||||
EC900002(900002, "加密时间戳参数非法", "加密时间戳不能为空"),
|
|
||||||
EC900003(900003, "加密随机字符串参数非法", "加密随机字符串不能为空"),
|
|
||||||
EC900004(900004, "不合法的aeskey", "检查aeskey是否符合规格,长度固定为43个字符,从a-z, A-Z, 0-9共62个字符中选取,是AESKey的Base64编码。解码后即为32字节长的AESKey"),
|
|
||||||
EC900005(900005, "签名不匹配", "检查签名计算的参数是否正确。请参考文档获取签名参数"),
|
|
||||||
EC900006(900006, "计算签名错误", "检查签名计算的参数是否正确。请参考文档获取签名参数"),
|
|
||||||
EC900007(900007, "计算加密文字错误", "检查是否安装JRE补丁或者对应的JRE版本是否正常。 请参考文档ISV应用开发准备工作"),
|
|
||||||
EC900008(900008, "计算解密文字错误", "检查是否安装JRE补丁或者对应的JRE版本是否正常。 请参考文档ISV应用开发准备工作"),
|
|
||||||
EC900009(900009, "计算解密文字长度不匹配", "检查aeskey是否符合规格。长度固定为43个字符,从a-z, A-Z, 0-9共62个字符中选取,是AESKey的Base64编码"),
|
|
||||||
EC900010(900010, "计算解密文字corpid不匹配", "检查corpid是否正确或者是否为当前企业的corpid"),
|
|
||||||
EC400010(400010, "激活的设备不存在(未绑定)", "无"),
|
|
||||||
EC400011(400011, "设备已经激活", "无"),
|
|
||||||
EC400020(400020, "无访问权限", "无"),
|
|
||||||
EC400021(400021, "密钥错误", "无"),
|
|
||||||
EC400022(400022, "设备不存在", "无"),
|
|
||||||
EC400023(400023, "用户不存在", "无"),
|
|
||||||
EC400040(400040, "回调不存在", "检查是否注册回调事件"),
|
|
||||||
EC400041(400041, "回调已经存在", "检查该回调事件是否已注册过"),
|
|
||||||
EC400042(400042, "企业不存在", "无"),
|
|
||||||
EC400043(400043, "企业不合法", "无"),
|
|
||||||
EC400050(400050, "回调地址无效", "检查回调地址是否正确或者符合地址格式"),
|
|
||||||
EC400051(400051, "回调地址访问异常", "注意回调地址必须部署到外网以便开发平台通过回调地址推送回调信息"),
|
|
||||||
EC400052(400052, "回调地址访返回数据错误", "无"),
|
|
||||||
EC400053(400053, "回调地址在黑名单中无法注册", "回调地址已添加黑名单,无法注册"),
|
|
||||||
EC400054(400054, "回调URL访问超时", "无"),
|
|
||||||
EC400055(400055, "回调设备不在线", "无"),
|
|
||||||
EC400056(400056, "回调访问设备失败", "无"),
|
|
||||||
EC400057(400057, "回调访问设备不存在", "无"),
|
|
||||||
EC420001(420001, "客户不存在", "无"),
|
|
||||||
EC420002(420002, "客户查询失败", "无"),
|
|
||||||
EC420003(420003, "联系人不存在", "无"),
|
|
||||||
EC420004(420004, "联系人查询失败", "无"),
|
|
||||||
EC420005(420005, "客户删除失败", "无"),
|
|
||||||
EC420006(420006, "联系人删除失败", "无"),
|
|
||||||
EC420007(420007, "跟进人绑定失败", "无"),
|
|
||||||
EC420008(420008, "客户id非法", "无"),
|
|
||||||
EC420009(420009, "跟进人id非法", "无"),
|
|
||||||
EC4200010(4200010, "客户联系人id非法", "无"),
|
|
||||||
EC4200011(4200011, "客户描述表单不存在", "无"),
|
|
||||||
EC4200012(4200012, "客户描述表单查询失败", "无"),
|
|
||||||
EC4200013(4200013, "联系人描述表单不存在", "无"),
|
|
||||||
EC4200014(4200014, "联系人描述表单查询失败", "无"),
|
|
||||||
EC4200015(4200015, "客户描述表单格式校验错误", "无"),
|
|
||||||
EC4200016(4200016, "客户描述表单格缺少固定字段", "无"),
|
|
||||||
EC4200017(4200017, "客户联系人描述表单格式校验错误", "无"),
|
|
||||||
EC4200018(4200018, "客户联系人描述表单格缺少固定字段", "无"),
|
|
||||||
EC4200019(4200019, "客户描述表单数据格式校验错误", "无"),
|
|
||||||
EC4200020(4200020, "客户描述表单数据缺少固定字段", "无"),
|
|
||||||
EC4200021(4200021, "客户联系人描述表单数据格式校验错误", "无"),
|
|
||||||
EC4200022(4200022, "客户联系人描述表单数据缺少固定字段", "无"),
|
|
||||||
EC800001(800001, "仅限ISV调用", "只有ISV微应用才能调用"),
|
|
||||||
EC41042(41042, "加密失败", "无"),
|
|
||||||
EC41043(41043, "解密失败", "无"),
|
|
||||||
EC40100(40100, "分机号已经存在", "无"),
|
|
||||||
EC40101(40101, "邮箱已经存在", "无"),
|
|
||||||
EC33013(33013, "企业自建微应用的个数过多,通过接口创建微应用受限", "此限制只针对企业自建微应用,对ISV应用没有限制"),
|
|
||||||
EC90017(90017, "此IP使用CorpId及CorpSecret调用接口的CorpId个数超过限制", "从该ip发起超过XX个corpid的请求被限制"),
|
|
||||||
EC40102(40102, "过期的临时授权码", "注意临时授权只能使用一次后就不能在使用。 需要重新执行授权操作有开放平台推送新的临时授权码"),
|
|
||||||
EC52020(52020, "未找到服务窗授权", "无"),
|
|
||||||
EC52021(52021, "未找到微应用授权", "无"),
|
|
||||||
EC52022(52022, "无效的jsapi类型", "无"),
|
|
||||||
EC52023(52023, "无效的服务窗agentid", "检查服务窗微应用是否停用或者删除"),
|
|
||||||
EC52024(52024, "无效的jsapi tag", "无"),
|
|
||||||
EC52025(52025, "无效的安全微应用", "无"),
|
|
||||||
EC52026(52026, "无效的安全微应用URL", "无"),
|
|
||||||
EC71014(71014, "获取套件下的服务窗应用失败", "无"),
|
|
||||||
EC72003(72003, "钉盘空间添加文件失败", "无"),
|
|
||||||
EC60128(60128, "无效的主管id", "无"),
|
|
||||||
EC200001(200001, "表单不能为空", "无"),
|
|
||||||
EC200004(200004, "APP_ID 不允许为空", "app_id为创建套件成功后,创建的ISV微应用的微应用ID。 可以登录开发者后台查看"),
|
|
||||||
EC200005(200005, "表单名称不允许为空", "无"),
|
|
||||||
EC200006(200006, "表单内容不允许为空", "无"),
|
|
||||||
EC200007(200007, "表单值不允许为空", "无"),
|
|
||||||
EC200008(200008, "表单uuid不存在", "无"),
|
|
||||||
EC400001(400001, "系统错误", "无"),
|
|
||||||
EC400002(400002, "参数错误", "检查参数是否符合规格。具体请参考当前接口的文档的参数说明和参数示例"),
|
|
||||||
EC400003(400003, "时间戳无效", "检查随机时间戳是否符合规格。具体请参考当前接口的文档的参数说明和参数示例"),
|
|
||||||
EC400004(400004, "随机数无效", "检查随机随机数是否符合规格。具体请参考当前接口的文档的参数说明和参数示例");
|
|
||||||
|
|
||||||
private int code;
|
|
||||||
private String desc;
|
|
||||||
private String solution;
|
|
||||||
|
|
||||||
AuthDingTalkErrorCode(int code, String desc, String solution) {
|
|
||||||
this.code = code;
|
|
||||||
this.desc = desc;
|
|
||||||
this.solution = solution;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AuthDingTalkErrorCode getErrorCode(int errorCode) {
|
|
||||||
AuthDingTalkErrorCode[] errorCodes = AuthDingTalkErrorCode.values();
|
|
||||||
for (AuthDingTalkErrorCode code : errorCodes) {
|
|
||||||
if (code.getCode() == errorCode) {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return EC1_MINUS;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCode() {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDesc() {
|
|
||||||
return desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSolution() {
|
|
||||||
return solution;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package me.zhyd.oauth.model;
|
package me.zhyd.oauth.model;
|
||||||
|
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Getter;
|
||||||
import me.zhyd.oauth.request.ResponseStatus;
|
import lombok.Setter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JustAuth统一授权响应类
|
* JustAuth统一授权响应类
|
||||||
@@ -11,8 +11,8 @@ import me.zhyd.oauth.request.ResponseStatus;
|
|||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
|
@Getter
|
||||||
@Builder
|
@Builder
|
||||||
@Data
|
|
||||||
public class AuthResponse<T> {
|
public class AuthResponse<T> {
|
||||||
/**
|
/**
|
||||||
* 授权响应状态码
|
* 授权响应状态码
|
||||||
@@ -28,4 +28,13 @@ public class AuthResponse<T> {
|
|||||||
* 授权响应数据,当且仅当 code = 2000 时返回
|
* 授权响应数据,当且仅当 code = 2000 时返回
|
||||||
*/
|
*/
|
||||||
private T data;
|
private T data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否请求成功
|
||||||
|
*
|
||||||
|
* @return true or false
|
||||||
|
*/
|
||||||
|
public boolean ok() {
|
||||||
|
return this.code == AuthResponseStatus.SUCCESS.getCode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-15
@@ -1,11 +1,16 @@
|
|||||||
package me.zhyd.oauth.request;
|
package me.zhyd.oauth.model;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
public enum ResponseStatus {
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum AuthResponseStatus {
|
||||||
SUCCESS(2000, "Success"),
|
SUCCESS(2000, "Success"),
|
||||||
FAILURE(5000, "Failure"),
|
FAILURE(5000, "Failure"),
|
||||||
NOT_IMPLEMENTED(5001, "Not Implemented"),
|
NOT_IMPLEMENTED(5001, "Not Implemented"),
|
||||||
@@ -13,22 +18,12 @@ public enum ResponseStatus {
|
|||||||
UNSUPPORTED(5003, "Unsupported operation"),
|
UNSUPPORTED(5003, "Unsupported operation"),
|
||||||
NO_AUTH_SOURCE(5004, "AuthSource cannot be null"),
|
NO_AUTH_SOURCE(5004, "AuthSource cannot be null"),
|
||||||
UNIDENTIFIED_PLATFORM(5005, "Unidentified platform"),
|
UNIDENTIFIED_PLATFORM(5005, "Unidentified platform"),
|
||||||
|
ILLEGAL_REDIRECT_URI(5006, "Illegal redirect uri"),
|
||||||
|
ILLEGAL_REQUEST(5007, "Illegal request"),
|
||||||
|
ILLEGAL_CODE(5008, "Illegal code"),
|
||||||
;
|
;
|
||||||
|
|
||||||
private int code;
|
private int code;
|
||||||
private String msg;
|
private String msg;
|
||||||
|
|
||||||
ResponseStatus(int code, String msg) {
|
|
||||||
this.code = code;
|
|
||||||
this.msg = msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCode() {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMsg() {
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package me.zhyd.oauth.model;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 授权来源(平台)
|
|
||||||
*
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public enum AuthSource {
|
|
||||||
GITHUB,
|
|
||||||
GITEE,
|
|
||||||
WEIBO,
|
|
||||||
DINGTALK,
|
|
||||||
BAIDU,
|
|
||||||
CSDN,
|
|
||||||
CODING,
|
|
||||||
OSCHINA,
|
|
||||||
TENCEN_CLOUD,
|
|
||||||
ALIPAY,
|
|
||||||
TAOBAO,
|
|
||||||
QQ,
|
|
||||||
WECHAT,
|
|
||||||
GOOGLE,
|
|
||||||
FACEBOOK,
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,8 @@ package me.zhyd.oauth.model;
|
|||||||
|
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 授权所需的token
|
* 授权所需的token
|
||||||
@@ -10,7 +12,8 @@ import lombok.Data;
|
|||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
@Data
|
@Getter
|
||||||
|
@Setter
|
||||||
@Builder
|
@Builder
|
||||||
public class AuthToken {
|
public class AuthToken {
|
||||||
private String accessToken;
|
private String accessToken;
|
||||||
@@ -19,6 +22,7 @@ public class AuthToken {
|
|||||||
private String uid;
|
private String uid;
|
||||||
private String openId;
|
private String openId;
|
||||||
private String accessCode;
|
private String accessCode;
|
||||||
|
private String unionId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Google附带属性
|
* Google附带属性
|
||||||
@@ -27,4 +31,10 @@ public class AuthToken {
|
|||||||
private String tokenType;
|
private String tokenType;
|
||||||
private String idToken;
|
private String idToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 小米附带属性
|
||||||
|
*/
|
||||||
|
private String macAlgorithm;
|
||||||
|
private String macKey;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
package me.zhyd.oauth.model;
|
package me.zhyd.oauth.model;
|
||||||
|
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import me.zhyd.oauth.config.AuthSource;
|
||||||
|
import me.zhyd.oauth.enums.AuthUserGender;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 授权成功后的用户信息,根据授权平台的不同,获取的数据完整性也不同
|
* 授权成功后的用户信息,根据授权平台的不同,获取的数据完整性也不同
|
||||||
@@ -10,9 +13,14 @@ import lombok.Data;
|
|||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
@Builder
|
@Builder
|
||||||
@Data
|
|
||||||
public class AuthUser {
|
public class AuthUser {
|
||||||
|
/**
|
||||||
|
* 用户第三方系统的唯一id。在调用方集成改组件时,可以用uuid + source唯一确定一个用户
|
||||||
|
*/
|
||||||
|
private String uuid;
|
||||||
/**
|
/**
|
||||||
* 用户名
|
* 用户名
|
||||||
*/
|
*/
|
||||||
@@ -57,8 +65,4 @@ public class AuthUser {
|
|||||||
* 用户授权的token信息
|
* 用户授权的token信息
|
||||||
*/
|
*/
|
||||||
private AuthToken token;
|
private AuthToken token;
|
||||||
/**
|
|
||||||
* 用户第三方系统的唯一id。在调用方集成改组件时,可以用uuid + source唯一确定一个用户
|
|
||||||
*/
|
|
||||||
private String uuid;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
package me.zhyd.oauth.model;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户性别
|
|
||||||
*
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public enum AuthUserGender {
|
|
||||||
MALE(1, "男"), FEMALE(0, "女"), UNKNOW(-1, "");
|
|
||||||
private int code;
|
|
||||||
private String desc;
|
|
||||||
|
|
||||||
AuthUserGender(int code, String desc) {
|
|
||||||
this.code = code;
|
|
||||||
this.desc = desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AuthUserGender getRealGender(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return UNKNOW;
|
|
||||||
}
|
|
||||||
String[] males = {"m", "男", "1", "male", "F"};
|
|
||||||
if (Arrays.asList(males).contains(code)) {
|
|
||||||
return MALE;
|
|
||||||
}
|
|
||||||
String[] females = {"f", "女", "0", "female"};
|
|
||||||
if (Arrays.asList(females).contains(code)) {
|
|
||||||
return FEMALE;
|
|
||||||
}
|
|
||||||
return UNKNOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCode() {
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDesc() {
|
|
||||||
return desc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,13 +8,14 @@ import com.alipay.api.request.AlipayUserInfoShareRequest;
|
|||||||
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
|
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
|
||||||
import com.alipay.api.response.AlipayUserInfoShareResponse;
|
import com.alipay.api.response.AlipayUserInfoShareResponse;
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
import me.zhyd.oauth.config.AuthConfig;
|
||||||
import me.zhyd.oauth.consts.ApiUrl;
|
import me.zhyd.oauth.config.AuthSource;
|
||||||
|
import me.zhyd.oauth.enums.AuthUserGender;
|
||||||
import me.zhyd.oauth.exception.AuthException;
|
import me.zhyd.oauth.exception.AuthException;
|
||||||
import me.zhyd.oauth.model.AuthSource;
|
import me.zhyd.oauth.model.AuthCallback;
|
||||||
import me.zhyd.oauth.model.AuthToken;
|
import me.zhyd.oauth.model.AuthToken;
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
import me.zhyd.oauth.model.AuthUserGender;
|
|
||||||
import me.zhyd.oauth.utils.StringUtils;
|
import me.zhyd.oauth.utils.StringUtils;
|
||||||
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付宝登录
|
* 支付宝登录
|
||||||
@@ -23,35 +24,36 @@ import me.zhyd.oauth.utils.StringUtils;
|
|||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
public class AuthAlipayRequest extends BaseAuthRequest {
|
public class AuthAlipayRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
private AlipayClient alipayClient;
|
private AlipayClient alipayClient;
|
||||||
|
|
||||||
public AuthAlipayRequest(AuthConfig config) {
|
public AuthAlipayRequest(AuthConfig config) {
|
||||||
super(config, AuthSource.ALIPAY);
|
super(config, AuthSource.ALIPAY);
|
||||||
this.alipayClient = new DefaultAlipayClient(ApiUrl.ALIPAY.accessToken(), config.getClientId(), config.getClientSecret(), "json", "UTF-8", config.getAlipayPublicKey(), "RSA2");
|
this.alipayClient = new DefaultAlipayClient(AuthSource.ALIPAY.accessToken(), config.getClientId(), config.getClientSecret(), "json", "UTF-8", config
|
||||||
|
.getAlipayPublicKey(), "RSA2");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthToken getAccessToken(String code) {
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
|
AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
|
||||||
request.setGrantType("authorization_code");
|
request.setGrantType("authorization_code");
|
||||||
request.setCode(code);
|
request.setCode(authCallback.getAuth_code());
|
||||||
AlipaySystemOauthTokenResponse response = null;
|
AlipaySystemOauthTokenResponse response = null;
|
||||||
try {
|
try {
|
||||||
response = this.alipayClient.execute(request);
|
response = this.alipayClient.execute(request);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new AuthException("Unable to get token from alipay using code [" + code + "]", e);
|
throw new AuthException(e);
|
||||||
}
|
}
|
||||||
if (!response.isSuccess()) {
|
if (!response.isSuccess()) {
|
||||||
throw new AuthException(response.getSubMsg());
|
throw new AuthException(response.getSubMsg());
|
||||||
}
|
}
|
||||||
return AuthToken.builder()
|
return AuthToken.builder()
|
||||||
.accessToken(response.getAccessToken())
|
.accessToken(response.getAccessToken())
|
||||||
.uid(response.getUserId())
|
.uid(response.getUserId())
|
||||||
.expireIn(Integer.parseInt(response.getExpiresIn()))
|
.expireIn(Integer.parseInt(response.getExpiresIn()))
|
||||||
.refreshToken(response.getRefreshToken())
|
.refreshToken(response.getRefreshToken())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -67,17 +69,34 @@ public class AuthAlipayRequest extends BaseAuthRequest {
|
|||||||
if (!response.isSuccess()) {
|
if (!response.isSuccess()) {
|
||||||
throw new AuthException(response.getSubMsg());
|
throw new AuthException(response.getSubMsg());
|
||||||
}
|
}
|
||||||
String province = response.getProvince(),
|
|
||||||
city = response.getCity();
|
String province = response.getProvince(), city = response.getCity();
|
||||||
|
String location = String.format("%s %s", StringUtils.isEmpty(province) ? "" : province, StringUtils.isEmpty(city) ? "" : city);
|
||||||
|
|
||||||
return AuthUser.builder()
|
return AuthUser.builder()
|
||||||
.uuid(response.getUserId())
|
.uuid(response.getUserId())
|
||||||
.username(response.getUserName())
|
.username(StringUtils.isEmpty(response.getUserName()) ? response.getNickName() : response.getUserName())
|
||||||
.nickname(response.getNickName())
|
.nickname(response.getNickName())
|
||||||
.avatar(response.getAvatar())
|
.avatar(response.getAvatar())
|
||||||
.location(String.format("%s %s", StringUtils.isEmpty(province) ? "" : province, StringUtils.isEmpty(city) ? "" : city))
|
.location(location)
|
||||||
.gender(AuthUserGender.getRealGender(response.getGender()))
|
.gender(AuthUserGender.getRealGender(response.getGender()))
|
||||||
.token(authToken)
|
.token(authToken)
|
||||||
.source(AuthSource.ALIPAY)
|
.source(source)
|
||||||
.build();
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回认证url,可自行跳转页面
|
||||||
|
*
|
||||||
|
* @return 返回授权地址
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
|
.queryParam("app_id", config.getClientId())
|
||||||
|
.queryParam("scope", "auth_user")
|
||||||
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
|
.queryParam("state", getRealState(config.getState()))
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ package me.zhyd.oauth.request;
|
|||||||
import cn.hutool.http.HttpRequest;
|
import cn.hutool.http.HttpRequest;
|
||||||
import cn.hutool.http.HttpResponse;
|
import cn.hutool.http.HttpResponse;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
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.exception.AuthException;
|
||||||
import me.zhyd.oauth.model.*;
|
import me.zhyd.oauth.model.*;
|
||||||
|
import me.zhyd.oauth.utils.StringUtils;
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,60 +18,102 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
public class AuthBaiduRequest extends BaseAuthRequest {
|
public class AuthBaiduRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
public AuthBaiduRequest(AuthConfig config) {
|
public AuthBaiduRequest(AuthConfig config) {
|
||||||
super(config, AuthSource.BAIDU);
|
super(config, AuthSource.BAIDU);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthToken getAccessToken(String code) {
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
String accessTokenUrl = UrlBuilder.getBaiduAccessTokenUrl(config.getClientId(), config.getClientSecret(), code, config.getRedirectUri());
|
HttpResponse response = doPostAuthorizationCode(authCallback.getCode());
|
||||||
HttpResponse response = HttpRequest.post(accessTokenUrl).execute();
|
return getAuthToken(response);
|
||||||
JSONObject accessTokenObject = JSONObject.parseObject(response.body());
|
|
||||||
AuthBaiduErrorCode errorCode = AuthBaiduErrorCode.getErrorCode(accessTokenObject.getString("error"));
|
|
||||||
if (!AuthBaiduErrorCode.OK.equals(errorCode)) {
|
|
||||||
throw new AuthException(errorCode.getDesc());
|
|
||||||
}
|
|
||||||
return AuthToken.builder()
|
|
||||||
.accessToken(accessTokenObject.getString("access_token"))
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
String accessToken = authToken.getAccessToken();
|
HttpResponse response = doGetUserInfo(authToken);
|
||||||
HttpResponse response = HttpRequest.get(UrlBuilder.getBaiduUserInfoUrl(accessToken)).execute();
|
|
||||||
String userInfo = response.body();
|
String userInfo = response.body();
|
||||||
JSONObject object = JSONObject.parseObject(userInfo);
|
JSONObject object = JSONObject.parseObject(userInfo);
|
||||||
AuthBaiduErrorCode errorCode = AuthBaiduErrorCode.getErrorCode(object.getString("error"));
|
this.checkResponse(object);
|
||||||
if (!AuthBaiduErrorCode.OK.equals(errorCode)) {
|
|
||||||
throw new AuthException(errorCode.getDesc());
|
|
||||||
}
|
|
||||||
return AuthUser.builder()
|
return AuthUser.builder()
|
||||||
.uuid(object.getString("userid"))
|
.uuid(object.getString("userid"))
|
||||||
.username(object.getString("username"))
|
.username(object.getString("username"))
|
||||||
.nickname(object.getString("username"))
|
.nickname(object.getString("username"))
|
||||||
.gender(AuthUserGender.getRealGender(object.getString("sex")))
|
.avatar(getAvatar(object))
|
||||||
.token(authToken)
|
.remark(object.getString("userdetail"))
|
||||||
.source(AuthSource.BAIDU)
|
.gender(AuthUserGender.getRealGender(object.getString("sex")))
|
||||||
.build();
|
.token(authToken)
|
||||||
|
.source(source)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getAvatar(JSONObject object) {
|
||||||
|
String protrait = object.getString("portrait");
|
||||||
|
return StringUtils.isEmpty(protrait) ? null : String.format("http://himg.bdimg.com/sys/portrait/item/%s.jpg", protrait);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AuthResponse revoke(AuthToken authToken) {
|
public AuthResponse revoke(AuthToken authToken) {
|
||||||
String accessToken = authToken.getAccessToken();
|
HttpResponse response = doGetRevoke(authToken);
|
||||||
HttpResponse response = HttpRequest.get(UrlBuilder.getBaiduRevokeUrl(accessToken)).execute();
|
JSONObject object = JSONObject.parseObject(response.body());
|
||||||
String userInfo = response.body();
|
this.checkResponse(object);
|
||||||
JSONObject object = JSONObject.parseObject(userInfo);
|
// 返回1表示取消授权成功,否则失败
|
||||||
if(object.containsKey("error_code")) {
|
AuthResponseStatus status = object.getIntValue("result") == 1 ? AuthResponseStatus.SUCCESS : AuthResponseStatus.FAILURE;
|
||||||
return AuthResponse.builder()
|
|
||||||
.code(ResponseStatus.FAILURE.getCode())
|
|
||||||
.msg(object.getString("error_msg"))
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
ResponseStatus status = object.getIntValue("result") == 1 ? ResponseStatus.SUCCESS : ResponseStatus.FAILURE;
|
|
||||||
return AuthResponse.builder().code(status.getCode()).msg(status.getMsg()).build();
|
return AuthResponse.builder().code(status.getCode()).msg(status.getMsg()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthResponse refresh(AuthToken authToken) {
|
||||||
|
String refreshUrl = UrlBuilder.fromBaseUrl(this.source.refresh())
|
||||||
|
.queryParam("grant_type", "refresh_token")
|
||||||
|
.queryParam("refresh_token", authToken.getRefreshToken())
|
||||||
|
.queryParam("client_id", this.config.getClientId())
|
||||||
|
.queryParam("client_secret", this.config.getClientSecret())
|
||||||
|
.build();
|
||||||
|
HttpResponse response = HttpRequest.get(refreshUrl).execute();
|
||||||
|
return AuthResponse.builder()
|
||||||
|
.code(AuthResponseStatus.SUCCESS.getCode())
|
||||||
|
.data(this.getAuthToken(response))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回认证url,可自行跳转页面
|
||||||
|
*
|
||||||
|
* @return 返回授权地址
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
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()))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查响应内容是否正确
|
||||||
|
*
|
||||||
|
* @param object 请求响应内容
|
||||||
|
*/
|
||||||
|
private void checkResponse(JSONObject object) {
|
||||||
|
if (object.containsKey("error") || object.containsKey("error_code")) {
|
||||||
|
String msg = object.containsKey("error_description") ? object.getString("error_description") : object.getString("error_msg");
|
||||||
|
throw new AuthException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuthToken getAuthToken(HttpResponse response) {
|
||||||
|
JSONObject accessTokenObject = JSONObject.parseObject(response.body());
|
||||||
|
this.checkResponse(accessTokenObject);
|
||||||
|
return AuthToken.builder()
|
||||||
|
.accessToken(accessTokenObject.getString("access_token"))
|
||||||
|
.refreshToken(accessTokenObject.getString("refresh_token"))
|
||||||
|
.scope(accessTokenObject.getString("scope"))
|
||||||
|
.expireIn(accessTokenObject.getIntValue("expires_in"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
package me.zhyd.oauth.request;
|
package me.zhyd.oauth.request;
|
||||||
|
|
||||||
import cn.hutool.http.HttpRequest;
|
|
||||||
import cn.hutool.http.HttpResponse;
|
import cn.hutool.http.HttpResponse;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
import me.zhyd.oauth.config.AuthConfig;
|
||||||
|
import me.zhyd.oauth.config.AuthSource;
|
||||||
import me.zhyd.oauth.exception.AuthException;
|
import me.zhyd.oauth.exception.AuthException;
|
||||||
import me.zhyd.oauth.model.AuthSource;
|
import me.zhyd.oauth.model.AuthCallback;
|
||||||
import me.zhyd.oauth.model.AuthToken;
|
import me.zhyd.oauth.model.AuthToken;
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
import me.zhyd.oauth.model.AuthUserGender;
|
import me.zhyd.oauth.enums.AuthUserGender;
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,47 +18,71 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
public class AuthCodingRequest extends BaseAuthRequest {
|
public class AuthCodingRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
public AuthCodingRequest(AuthConfig config) {
|
public AuthCodingRequest(AuthConfig config) {
|
||||||
super(config, AuthSource.CODING);
|
super(config, AuthSource.CODING);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthToken getAccessToken(String code) {
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
String accessTokenUrl = UrlBuilder.getCodingAccessTokenUrl(config.getClientId(), config.getClientSecret(), code);
|
HttpResponse response = doGetAuthorizationCode(authCallback.getCode());
|
||||||
HttpResponse response = HttpRequest.get(accessTokenUrl).execute();
|
|
||||||
JSONObject accessTokenObject = JSONObject.parseObject(response.body());
|
JSONObject accessTokenObject = JSONObject.parseObject(response.body());
|
||||||
if (accessTokenObject.getIntValue("code") != 0) {
|
this.checkResponse(accessTokenObject);
|
||||||
throw new AuthException("Unable to get token from coding using code [" + code + "]");
|
|
||||||
}
|
|
||||||
return AuthToken.builder()
|
return AuthToken.builder()
|
||||||
.accessToken(accessTokenObject.getString("access_token"))
|
.accessToken(accessTokenObject.getString("access_token"))
|
||||||
.build();
|
.expireIn(accessTokenObject.getIntValue("expires_in"))
|
||||||
|
.refreshToken(accessTokenObject.getString("refresh_token"))
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
String accessToken = authToken.getAccessToken();
|
HttpResponse response = doGetUserInfo(authToken);
|
||||||
HttpResponse response = HttpRequest.get(UrlBuilder.getCodingUserInfoUrl(accessToken)).execute();
|
|
||||||
JSONObject object = JSONObject.parseObject(response.body());
|
JSONObject object = JSONObject.parseObject(response.body());
|
||||||
|
this.checkResponse(object);
|
||||||
|
|
||||||
|
object = object.getJSONObject("data");
|
||||||
|
return AuthUser.builder()
|
||||||
|
.uuid(object.getString("id"))
|
||||||
|
.username(object.getString("name"))
|
||||||
|
.avatar("https://coding.net/" + object.getString("avatar"))
|
||||||
|
.blog("https://coding.net/" + object.getString("path"))
|
||||||
|
.nickname(object.getString("name"))
|
||||||
|
.company(object.getString("company"))
|
||||||
|
.location(object.getString("location"))
|
||||||
|
.gender(AuthUserGender.getRealGender(object.getString("sex")))
|
||||||
|
.email(object.getString("email"))
|
||||||
|
.remark(object.getString("slogan"))
|
||||||
|
.token(authToken)
|
||||||
|
.source(source)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查响应内容是否正确
|
||||||
|
*
|
||||||
|
* @param object 请求响应内容
|
||||||
|
*/
|
||||||
|
private void checkResponse(JSONObject object) {
|
||||||
if (object.getIntValue("code") != 0) {
|
if (object.getIntValue("code") != 0) {
|
||||||
throw new AuthException(object.getString("msg"));
|
throw new AuthException(object.getString("msg"));
|
||||||
}
|
}
|
||||||
object = object.getJSONObject("data");
|
}
|
||||||
return AuthUser.builder()
|
|
||||||
.uuid(object.getString("id"))
|
/**
|
||||||
.username(object.getString("name"))
|
* 返回认证url,可自行跳转页面
|
||||||
.avatar("https://coding.net/" + object.getString("avatar"))
|
*
|
||||||
.blog("https://coding.net/" + object.getString("path"))
|
* @return 返回授权地址
|
||||||
.nickname(object.getString("name"))
|
*/
|
||||||
.company(object.getString("company"))
|
@Override
|
||||||
.location(object.getString("location"))
|
public String authorize() {
|
||||||
.gender(AuthUserGender.getRealGender(object.getString("sex")))
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
.email(object.getString("email"))
|
.queryParam("response_type", "code")
|
||||||
.remark(object.getString("slogan"))
|
.queryParam("client_id", config.getClientId())
|
||||||
.token(authToken)
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
.source(AuthSource.CODING)
|
.queryParam("scope", "user")
|
||||||
.build();
|
.queryParam("state", getRealState(config.getState()))
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
package me.zhyd.oauth.request;
|
package me.zhyd.oauth.request;
|
||||||
|
|
||||||
import cn.hutool.http.HttpRequest;
|
|
||||||
import cn.hutool.http.HttpResponse;
|
import cn.hutool.http.HttpResponse;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
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.exception.AuthException;
|
||||||
import me.zhyd.oauth.model.AuthSource;
|
import me.zhyd.oauth.model.AuthCallback;
|
||||||
import me.zhyd.oauth.model.AuthToken;
|
import me.zhyd.oauth.model.AuthToken;
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CSDN登录
|
* CSDN登录
|
||||||
@@ -17,40 +17,45 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
public class AuthCsdnRequest extends BaseAuthRequest {
|
@Deprecated
|
||||||
|
public class AuthCsdnRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
public AuthCsdnRequest(AuthConfig config) {
|
public AuthCsdnRequest(AuthConfig config) {
|
||||||
super(config, AuthSource.CSDN);
|
super(config, AuthSource.CSDN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthToken getAccessToken(String code) {
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
String accessTokenUrl = UrlBuilder.getCsdnAccessTokenUrl(config.getClientId(), config.getClientSecret(), code, config.getRedirectUri());
|
HttpResponse response = doPostAuthorizationCode(authCallback.getCode());
|
||||||
HttpResponse response = HttpRequest.post(accessTokenUrl).execute();
|
|
||||||
JSONObject accessTokenObject = JSONObject.parseObject(response.body());
|
JSONObject accessTokenObject = JSONObject.parseObject(response.body());
|
||||||
if (accessTokenObject.containsKey("error_code")) {
|
this.checkResponse(accessTokenObject);
|
||||||
throw new AuthException("Unable to get token from csdn using code [" + code + "]");
|
return AuthToken.builder().accessToken(accessTokenObject.getString("access_token")).build();
|
||||||
}
|
|
||||||
return AuthToken.builder()
|
|
||||||
.accessToken(accessTokenObject.getString("access_token"))
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
String accessToken = authToken.getAccessToken();
|
HttpResponse response = doGetUserInfo(authToken);
|
||||||
HttpResponse response = HttpRequest.get(UrlBuilder.getCsdnUserInfoUrl(accessToken)).execute();
|
|
||||||
JSONObject object = JSONObject.parseObject(response.body());
|
JSONObject object = JSONObject.parseObject(response.body());
|
||||||
|
this.checkResponse(object);
|
||||||
|
return AuthUser.builder()
|
||||||
|
.uuid(object.getString("username"))
|
||||||
|
.username(object.getString("username"))
|
||||||
|
.remark(object.getString("description"))
|
||||||
|
.blog(object.getString("website"))
|
||||||
|
.gender(AuthUserGender.UNKNOWN)
|
||||||
|
.token(authToken)
|
||||||
|
.source(source)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查响应内容是否正确
|
||||||
|
*
|
||||||
|
* @param object 请求响应内容
|
||||||
|
*/
|
||||||
|
private void checkResponse(JSONObject object) {
|
||||||
if (object.containsKey("error_code")) {
|
if (object.containsKey("error_code")) {
|
||||||
throw new AuthException(object.getString("error"));
|
throw new AuthException(object.getString("error"));
|
||||||
}
|
}
|
||||||
return AuthUser.builder()
|
|
||||||
.uuid(object.getString("username"))
|
|
||||||
.username(object.getString("username"))
|
|
||||||
.remark(object.getString("description"))
|
|
||||||
.blog(object.getString("website"))
|
|
||||||
.token(authToken)
|
|
||||||
.source(AuthSource.CSDN)
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,201 @@
|
|||||||
|
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.config.AuthConfig;
|
||||||
|
import me.zhyd.oauth.config.AuthSource;
|
||||||
|
import me.zhyd.oauth.exception.AuthException;
|
||||||
|
import me.zhyd.oauth.model.*;
|
||||||
|
import me.zhyd.oauth.utils.AuthChecker;
|
||||||
|
import me.zhyd.oauth.utils.StringUtils;
|
||||||
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认的request处理类
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @author yangkai.shen (https://xkcoding.com)
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.8
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public abstract class AuthDefaultRequest implements AuthRequest {
|
||||||
|
protected AuthConfig config;
|
||||||
|
protected AuthSource source;
|
||||||
|
|
||||||
|
public AuthDefaultRequest(AuthConfig config, AuthSource source) {
|
||||||
|
this.config = config;
|
||||||
|
this.source = source;
|
||||||
|
if (!AuthChecker.isSupportedAuth(config, source)) {
|
||||||
|
throw new AuthException(AuthResponseStatus.PARAMETER_INCOMPLETE);
|
||||||
|
}
|
||||||
|
// 校验配置合法性
|
||||||
|
AuthChecker.checkConfig(config, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract AuthToken getAccessToken(AuthCallback authCallback);
|
||||||
|
|
||||||
|
protected abstract AuthUser getUserInfo(AuthToken authToken);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthResponse login(AuthCallback authCallback) {
|
||||||
|
try {
|
||||||
|
AuthChecker.checkCode(source == AuthSource.ALIPAY ? authCallback.getAuth_code() : authCallback.getCode());
|
||||||
|
AuthChecker.checkState(authCallback.getState(), config.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);
|
||||||
|
return this.responseError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuthResponse responseError(Exception e) {
|
||||||
|
int errorCode = AuthResponseStatus.FAILURE.getCode();
|
||||||
|
if (e instanceof AuthException) {
|
||||||
|
errorCode = ((AuthException) e).getErrorCode();
|
||||||
|
}
|
||||||
|
return AuthResponse.builder().code(errorCode).msg(e.getMessage()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回认证url,可自行跳转页面
|
||||||
|
*
|
||||||
|
* @return 返回授权地址
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
|
.queryParam("response_type", "code")
|
||||||
|
.queryParam("client_id", config.getClientId())
|
||||||
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
|
.queryParam("state", getRealState(config.getState()))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取accessToken的url
|
||||||
|
*
|
||||||
|
* @param code 授权码
|
||||||
|
* @return 返回获取accessToken的url
|
||||||
|
*/
|
||||||
|
protected String accessTokenUrl(String code) {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.accessToken())
|
||||||
|
.queryParam("code", code)
|
||||||
|
.queryParam("client_id", config.getClientId())
|
||||||
|
.queryParam("client_secret", config.getClientSecret())
|
||||||
|
.queryParam("grant_type", "authorization_code")
|
||||||
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取accessToken的url
|
||||||
|
*
|
||||||
|
* @param refreshToken refreshToken
|
||||||
|
* @return 返回获取accessToken的url
|
||||||
|
*/
|
||||||
|
protected String refreshTokenUrl(String refreshToken) {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.refresh())
|
||||||
|
.queryParam("client_id", config.getClientId())
|
||||||
|
.queryParam("client_secret", config.getClientSecret())
|
||||||
|
.queryParam("refresh_token", refreshToken)
|
||||||
|
.queryParam("grant_type", "refresh_token")
|
||||||
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取userInfo的url
|
||||||
|
*
|
||||||
|
* @param authToken token
|
||||||
|
* @return 返回获取userInfo的url
|
||||||
|
*/
|
||||||
|
protected String userInfoUrl(AuthToken authToken) {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.userInfo()).queryParam("access_token", authToken.getAccessToken()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取revoke authorization的url
|
||||||
|
*
|
||||||
|
* @param authToken token
|
||||||
|
* @return 返回获取revoke authorization的url
|
||||||
|
*/
|
||||||
|
protected String revokeUrl(AuthToken authToken) {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.revoke()).queryParam("access_token", authToken.getAccessToken()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取state,如果为空, 则默认去当前日期的时间戳
|
||||||
|
*
|
||||||
|
* @param state 原始的state
|
||||||
|
* @return 返回不为null的state
|
||||||
|
*/
|
||||||
|
protected String getRealState(String state) {
|
||||||
|
return StringUtils.isEmpty(state) ? String.valueOf(System.currentTimeMillis()) : state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用的 authorizationCode 协议
|
||||||
|
*
|
||||||
|
* @param code code码
|
||||||
|
* @return HttpResponse
|
||||||
|
*/
|
||||||
|
protected HttpResponse doPostAuthorizationCode(String code) {
|
||||||
|
return HttpRequest.post(accessTokenUrl(code)).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用的 authorizationCode 协议
|
||||||
|
*
|
||||||
|
* @param code code码
|
||||||
|
* @return HttpResponse
|
||||||
|
*/
|
||||||
|
protected HttpResponse doGetAuthorizationCode(String code) {
|
||||||
|
return HttpRequest.get(accessTokenUrl(code)).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用的 用户信息
|
||||||
|
*
|
||||||
|
* @param authToken token封装
|
||||||
|
* @return HttpResponse
|
||||||
|
*/
|
||||||
|
protected HttpResponse doPostUserInfo(AuthToken authToken) {
|
||||||
|
return HttpRequest.post(userInfoUrl(authToken)).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用的 用户信息
|
||||||
|
*
|
||||||
|
* @param authToken token封装
|
||||||
|
* @return HttpResponse
|
||||||
|
*/
|
||||||
|
protected HttpResponse doGetUserInfo(AuthToken authToken) {
|
||||||
|
return HttpRequest.get(userInfoUrl(authToken)).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用的post形式的取消授权方法
|
||||||
|
*
|
||||||
|
* @param authToken token封装
|
||||||
|
* @return HttpResponse
|
||||||
|
*/
|
||||||
|
protected HttpResponse doPostRevoke(AuthToken authToken) {
|
||||||
|
return HttpRequest.post(revokeUrl(authToken)).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用的post形式的取消授权方法
|
||||||
|
*
|
||||||
|
* @param authToken token封装
|
||||||
|
* @return HttpResponse
|
||||||
|
*/
|
||||||
|
protected HttpResponse doGetRevoke(AuthToken authToken) {
|
||||||
|
return HttpRequest.get(revokeUrl(authToken)).execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,18 +2,18 @@ package me.zhyd.oauth.request;
|
|||||||
|
|
||||||
import cn.hutool.http.HttpRequest;
|
import cn.hutool.http.HttpRequest;
|
||||||
import cn.hutool.http.HttpResponse;
|
import cn.hutool.http.HttpResponse;
|
||||||
import cn.hutool.json.JSONObject;
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
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.exception.AuthException;
|
||||||
import me.zhyd.oauth.model.AuthDingTalkErrorCode;
|
import me.zhyd.oauth.model.AuthCallback;
|
||||||
import me.zhyd.oauth.model.AuthSource;
|
|
||||||
import me.zhyd.oauth.model.AuthToken;
|
import me.zhyd.oauth.model.AuthToken;
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
import me.zhyd.oauth.utils.GlobalAuthUtil;
|
import me.zhyd.oauth.utils.GlobalAuthUtil;
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 钉钉登录
|
* 钉钉登录
|
||||||
*
|
*
|
||||||
@@ -21,40 +21,74 @@ import java.util.Objects;
|
|||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
public class AuthDingTalkRequest extends BaseAuthRequest {
|
public class AuthDingTalkRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
public AuthDingTalkRequest(AuthConfig config) {
|
public AuthDingTalkRequest(AuthConfig config) {
|
||||||
super(config, AuthSource.DINGTALK);
|
super(config, AuthSource.DINGTALK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthToken getAccessToken(String code) {
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
return AuthToken.builder()
|
return AuthToken.builder().accessCode(authCallback.getCode()).build();
|
||||||
.accessCode(code)
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
String code = authToken.getAccessCode();
|
String code = authToken.getAccessCode();
|
||||||
// 根据timestamp, appSecret计算签名值
|
JSONObject param = new JSONObject();
|
||||||
String stringToSign = System.currentTimeMillis() + "";
|
param.put("tmp_auth_code", code);
|
||||||
String urlEncodeSignature = GlobalAuthUtil.generateDingTalkSignature(config.getClientSecret(), stringToSign);
|
HttpResponse response = HttpRequest.post(userInfoUrl(authToken)).body(param.toJSONString()).execute();
|
||||||
HttpResponse response = HttpRequest.post(UrlBuilder.getDingTalkUserInfoUrl(urlEncodeSignature, stringToSign, config.getClientId()))
|
JSONObject object = JSON.parseObject(response.body());
|
||||||
.body(Objects.requireNonNull(new JSONObject().put("tmp_auth_code", code)))
|
if (object.getIntValue("errcode") != 0) {
|
||||||
.execute();
|
throw new AuthException(object.getString("errmsg"));
|
||||||
String userInfo = response.body();
|
|
||||||
JSONObject object = new JSONObject(userInfo);
|
|
||||||
AuthDingTalkErrorCode errorCode = AuthDingTalkErrorCode.getErrorCode(object.getInt("errcode"));
|
|
||||||
if (!AuthDingTalkErrorCode.EC0.equals(errorCode)) {
|
|
||||||
throw new AuthException(errorCode.getDesc());
|
|
||||||
}
|
}
|
||||||
object = object.getJSONObject("user_info");
|
object = object.getJSONObject("user_info");
|
||||||
|
AuthToken token = AuthToken.builder()
|
||||||
|
.openId(object.getString("openid"))
|
||||||
|
.unionId(object.getString("unionid"))
|
||||||
|
.build();
|
||||||
return AuthUser.builder()
|
return AuthUser.builder()
|
||||||
.uuid(object.getStr("openid"))
|
.uuid(object.getString("unionid"))
|
||||||
.nickname(object.getStr("nick"))
|
.nickname(object.getString("nick"))
|
||||||
.username(object.getStr("nick"))
|
.username(object.getString("nick"))
|
||||||
.source(AuthSource.DINGTALK)
|
.gender(AuthUserGender.UNKNOWN)
|
||||||
.build();
|
.source(source)
|
||||||
|
.token(token)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回认证url,可自行跳转页面
|
||||||
|
*
|
||||||
|
* @return 返回授权地址
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
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()))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取userInfo的url
|
||||||
|
*
|
||||||
|
* @param authToken 用户授权后的token
|
||||||
|
* @return 返回获取userInfo的url
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String userInfoUrl(AuthToken authToken) {
|
||||||
|
// 根据timestamp, appSecret计算签名值
|
||||||
|
String timestamp = System.currentTimeMillis() + "";
|
||||||
|
String urlEncodeSignature = GlobalAuthUtil.generateDingTalkSignature(config.getClientSecret(), timestamp);
|
||||||
|
|
||||||
|
return UrlBuilder.fromBaseUrl(source.userInfo())
|
||||||
|
.queryParam("signature", urlEncodeSignature)
|
||||||
|
.queryParam("timestamp", timestamp)
|
||||||
|
.queryParam("accessKey", config.getClientId())
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,151 @@
|
|||||||
|
package me.zhyd.oauth.request;
|
||||||
|
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
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.*;
|
||||||
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 抖音登录
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.8
|
||||||
|
*/
|
||||||
|
public class AuthDouyinRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
|
public AuthDouyinRequest(AuthConfig config) {
|
||||||
|
super(config, AuthSource.DOUYIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
|
return this.getToken(accessTokenUrl(authCallback.getCode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
|
HttpResponse response = doGetUserInfo(authToken);
|
||||||
|
JSONObject userInfoObject = JSONObject.parseObject(response.body());
|
||||||
|
this.checkResponse(userInfoObject);
|
||||||
|
return AuthUser.builder()
|
||||||
|
.uuid(userInfoObject.getString("union_id"))
|
||||||
|
.username(userInfoObject.getString("nickname"))
|
||||||
|
.nickname(userInfoObject.getString("nickname"))
|
||||||
|
.avatar(userInfoObject.getString("avatar"))
|
||||||
|
.remark(userInfoObject.getString("description"))
|
||||||
|
.gender(AuthUserGender.UNKNOWN)
|
||||||
|
.token(authToken)
|
||||||
|
.source(source)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthResponse refresh(AuthToken oldToken) {
|
||||||
|
return AuthResponse.builder()
|
||||||
|
.code(AuthResponseStatus.SUCCESS.getCode())
|
||||||
|
.data(getToken(refreshTokenUrl(oldToken.getRefreshToken())))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查响应内容是否正确
|
||||||
|
*
|
||||||
|
* @param object 请求响应内容
|
||||||
|
*/
|
||||||
|
private void checkResponse(JSONObject object) {
|
||||||
|
String message = object.getString("message");
|
||||||
|
JSONObject data = object.getJSONObject("data");
|
||||||
|
int errorCode = data.getIntValue("error_code");
|
||||||
|
if ("error".equals(message) || errorCode != 0) {
|
||||||
|
throw new AuthException(errorCode, data.getString("description"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取token,适用于获取access_token和刷新token
|
||||||
|
*
|
||||||
|
* @param accessTokenUrl 实际请求token的地址
|
||||||
|
* @return token对象
|
||||||
|
*/
|
||||||
|
private AuthToken getToken(String accessTokenUrl) {
|
||||||
|
HttpResponse response = HttpRequest.post(accessTokenUrl).execute();
|
||||||
|
String accessTokenStr = response.body();
|
||||||
|
JSONObject object = JSONObject.parseObject(accessTokenStr);
|
||||||
|
this.checkResponse(object);
|
||||||
|
return AuthToken.builder()
|
||||||
|
.accessToken(object.getString("access_token"))
|
||||||
|
.openId(object.getString("open_id"))
|
||||||
|
.expireIn(object.getIntValue("expires_in"))
|
||||||
|
.refreshToken(object.getString("refresh_token"))
|
||||||
|
.scope(object.getString("scope"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回认证url,可自行跳转页面
|
||||||
|
*
|
||||||
|
* @return 返回授权地址
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
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")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取accessToken的url
|
||||||
|
*
|
||||||
|
* @param code oauth的授权码
|
||||||
|
* @return 返回获取accessToken的url
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String accessTokenUrl(String code) {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.accessToken())
|
||||||
|
.queryParam("code", code)
|
||||||
|
.queryParam("client_key", config.getClientId())
|
||||||
|
.queryParam("client_secret", config.getClientSecret())
|
||||||
|
.queryParam("grant_type", "authorization_code")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取userInfo的url
|
||||||
|
*
|
||||||
|
* @param authToken oauth返回的token
|
||||||
|
* @return 返回获取userInfo的url
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String userInfoUrl(AuthToken authToken) {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.userInfo())
|
||||||
|
.queryParam("access_token", authToken.getAccessToken())
|
||||||
|
.queryParam("open_id", authToken.getOpenId())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取accessToken的url
|
||||||
|
*
|
||||||
|
* @param refreshToken oauth返回的refreshtoken
|
||||||
|
* @return 返回获取accessToken的url
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String refreshTokenUrl(String refreshToken) {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.refresh())
|
||||||
|
.queryParam("client_key", config.getClientId())
|
||||||
|
.queryParam("refresh_token", refreshToken)
|
||||||
|
.queryParam("grant_type", "refresh_token")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
package me.zhyd.oauth.request;
|
package me.zhyd.oauth.request;
|
||||||
|
|
||||||
import cn.hutool.http.HttpRequest;
|
|
||||||
import cn.hutool.http.HttpResponse;
|
import cn.hutool.http.HttpResponse;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
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.exception.AuthException;
|
||||||
import me.zhyd.oauth.model.AuthSource;
|
import me.zhyd.oauth.model.AuthCallback;
|
||||||
import me.zhyd.oauth.model.AuthToken;
|
import me.zhyd.oauth.model.AuthToken;
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
import me.zhyd.oauth.model.AuthUserGender;
|
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,38 +18,44 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
public class AuthFacebookRequest extends BaseAuthRequest {
|
public class AuthFacebookRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
public AuthFacebookRequest(AuthConfig config) {
|
public AuthFacebookRequest(AuthConfig config) {
|
||||||
super(config, AuthSource.FACEBOOK);
|
super(config, AuthSource.FACEBOOK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthToken getAccessToken(String code) {
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
String accessTokenUrl = UrlBuilder.getFacebookAccessTokenUrl(config.getClientId(), config.getClientSecret(), code, config.getRedirectUri());
|
HttpResponse response = doPostAuthorizationCode(authCallback.getCode());
|
||||||
HttpResponse response = HttpRequest.post(accessTokenUrl).execute();
|
JSONObject accessTokenObject = JSONObject.parseObject(response.body());
|
||||||
JSONObject object = JSONObject.parseObject(response.body());
|
this.checkResponse(accessTokenObject);
|
||||||
|
|
||||||
if (object.containsKey("error")) {
|
|
||||||
throw new AuthException(object.getJSONObject("error").getString("message"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return AuthToken.builder()
|
return AuthToken.builder()
|
||||||
.accessToken(object.getString("access_token"))
|
.accessToken(accessTokenObject.getString("access_token"))
|
||||||
.expireIn(object.getIntValue("expires_in"))
|
.expireIn(accessTokenObject.getIntValue("expires_in"))
|
||||||
.tokenType(object.getString("token_type"))
|
.tokenType(accessTokenObject.getString("token_type"))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
String accessToken = authToken.getAccessToken();
|
HttpResponse response = doGetUserInfo(authToken);
|
||||||
HttpResponse response = HttpRequest.get(UrlBuilder.getFacebookUserInfoUrl(accessToken)).execute();
|
|
||||||
String userInfo = response.body();
|
String userInfo = response.body();
|
||||||
JSONObject object = JSONObject.parseObject(userInfo);
|
JSONObject object = JSONObject.parseObject(userInfo);
|
||||||
if (object.containsKey("error")) {
|
this.checkResponse(object);
|
||||||
throw new AuthException(object.getJSONObject("error").getString("message"));
|
return AuthUser.builder()
|
||||||
}
|
.uuid(object.getString("id"))
|
||||||
|
.username(object.getString("name"))
|
||||||
|
.nickname(object.getString("name"))
|
||||||
|
.avatar(getUserPicture(object))
|
||||||
|
.location(object.getString("locale"))
|
||||||
|
.email(object.getString("email"))
|
||||||
|
.gender(AuthUserGender.getRealGender(object.getString("gender")))
|
||||||
|
.token(authToken)
|
||||||
|
.source(source)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getUserPicture(JSONObject object) {
|
||||||
String picture = null;
|
String picture = null;
|
||||||
if (object.containsKey("picture")) {
|
if (object.containsKey("picture")) {
|
||||||
JSONObject pictureObj = object.getJSONObject("picture");
|
JSONObject pictureObj = object.getJSONObject("picture");
|
||||||
@@ -58,16 +64,31 @@ public class AuthFacebookRequest extends BaseAuthRequest {
|
|||||||
picture = pictureObj.getString("url");
|
picture = pictureObj.getString("url");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return AuthUser.builder()
|
return picture;
|
||||||
.uuid(object.getString("id"))
|
}
|
||||||
.username(object.getString("name"))
|
|
||||||
.nickname(object.getString("name"))
|
/**
|
||||||
.avatar(picture)
|
* 返回获取userInfo的url
|
||||||
.location(object.getString("locale"))
|
*
|
||||||
.email(object.getString("email"))
|
* @param authToken 用户token
|
||||||
.gender(AuthUserGender.getRealGender(object.getString("gender")))
|
* @return 返回获取userInfo的url
|
||||||
.token(authToken)
|
*/
|
||||||
.source(AuthSource.FACEBOOK)
|
@Override
|
||||||
.build();
|
protected String userInfoUrl(AuthToken authToken) {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.userInfo())
|
||||||
|
.queryParam("access_token", authToken.getAccessToken())
|
||||||
|
.queryParam("fields", "id,name,birthday,gender,hometown,email,devices,picture.width(400)")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查响应内容是否正确
|
||||||
|
*
|
||||||
|
* @param object 请求响应内容
|
||||||
|
*/
|
||||||
|
private void checkResponse(JSONObject object) {
|
||||||
|
if (object.containsKey("error")) {
|
||||||
|
throw new AuthException(object.getJSONObject("error").getString("message"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
package me.zhyd.oauth.request;
|
package me.zhyd.oauth.request;
|
||||||
|
|
||||||
import cn.hutool.http.HttpRequest;
|
|
||||||
import cn.hutool.http.HttpResponse;
|
import cn.hutool.http.HttpResponse;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
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.exception.AuthException;
|
||||||
import me.zhyd.oauth.model.AuthSource;
|
import me.zhyd.oauth.model.AuthCallback;
|
||||||
import me.zhyd.oauth.model.AuthToken;
|
import me.zhyd.oauth.model.AuthToken;
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gitee登录
|
* Gitee登录
|
||||||
@@ -17,43 +17,56 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
public class AuthGiteeRequest extends BaseAuthRequest {
|
public class AuthGiteeRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
public AuthGiteeRequest(AuthConfig config) {
|
public AuthGiteeRequest(AuthConfig config) {
|
||||||
super(config, AuthSource.GITEE);
|
super(config, AuthSource.GITEE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthToken getAccessToken(String code) {
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
String accessTokenUrl = UrlBuilder.getGiteeAccessTokenUrl(config.getClientId(), config.getClientSecret(), code, config.getRedirectUri());
|
HttpResponse response = doPostAuthorizationCode(authCallback.getCode());
|
||||||
HttpResponse response = HttpRequest.post(accessTokenUrl).execute();
|
|
||||||
JSONObject accessTokenObject = JSONObject.parseObject(response.body());
|
JSONObject accessTokenObject = JSONObject.parseObject(response.body());
|
||||||
if (accessTokenObject.containsKey("error")) {
|
this.checkResponse(accessTokenObject);
|
||||||
throw new AuthException("Unable to get token from gitee using code [" + code + "]");
|
|
||||||
}
|
|
||||||
return AuthToken.builder()
|
return AuthToken.builder()
|
||||||
.accessToken(accessTokenObject.getString("access_token"))
|
.accessToken(accessTokenObject.getString("access_token"))
|
||||||
.build();
|
.refreshToken(accessTokenObject.getString("refresh_token"))
|
||||||
|
.scope(accessTokenObject.getString("scope"))
|
||||||
|
.tokenType(accessTokenObject.getString("token_type"))
|
||||||
|
.expireIn(accessTokenObject.getIntValue("expires_in"))
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
String accessToken = authToken.getAccessToken();
|
HttpResponse response = doGetUserInfo(authToken);
|
||||||
HttpResponse response = HttpRequest.get(UrlBuilder.getGiteeUserInfoUrl(accessToken)).execute();
|
|
||||||
String userInfo = response.body();
|
String userInfo = response.body();
|
||||||
JSONObject object = JSONObject.parseObject(userInfo);
|
JSONObject object = JSONObject.parseObject(userInfo);
|
||||||
|
this.checkResponse(object);
|
||||||
return AuthUser.builder()
|
return AuthUser.builder()
|
||||||
.uuid(object.getString("id"))
|
.uuid(object.getString("id"))
|
||||||
.username(object.getString("login"))
|
.username(object.getString("login"))
|
||||||
.avatar(object.getString("avatar_url"))
|
.avatar(object.getString("avatar_url"))
|
||||||
.blog(object.getString("blog"))
|
.blog(object.getString("blog"))
|
||||||
.nickname(object.getString("name"))
|
.nickname(object.getString("name"))
|
||||||
.company(object.getString("company"))
|
.company(object.getString("company"))
|
||||||
.location(object.getString("address"))
|
.location(object.getString("address"))
|
||||||
.email(object.getString("email"))
|
.email(object.getString("email"))
|
||||||
.remark(object.getString("bio"))
|
.remark(object.getString("bio"))
|
||||||
.token(authToken)
|
.gender(AuthUserGender.UNKNOWN)
|
||||||
.source(AuthSource.GITEE)
|
.token(authToken)
|
||||||
.build();
|
.source(source)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查响应内容是否正确
|
||||||
|
*
|
||||||
|
* @param object 请求响应内容
|
||||||
|
*/
|
||||||
|
private void checkResponse(JSONObject object) {
|
||||||
|
if (object.containsKey("error")) {
|
||||||
|
throw new AuthException(object.getString("error_description"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
package me.zhyd.oauth.request;
|
package me.zhyd.oauth.request;
|
||||||
|
|
||||||
import cn.hutool.http.HttpRequest;
|
|
||||||
import cn.hutool.http.HttpResponse;
|
import cn.hutool.http.HttpResponse;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
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.exception.AuthException;
|
||||||
import me.zhyd.oauth.model.AuthSource;
|
import me.zhyd.oauth.model.AuthCallback;
|
||||||
import me.zhyd.oauth.model.AuthToken;
|
import me.zhyd.oauth.model.AuthToken;
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
import me.zhyd.oauth.utils.GlobalAuthUtil;
|
import me.zhyd.oauth.utils.GlobalAuthUtil;
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -20,43 +20,55 @@ import java.util.Map;
|
|||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
public class AuthGithubRequest extends BaseAuthRequest {
|
public class AuthGithubRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
public AuthGithubRequest(AuthConfig config) {
|
public AuthGithubRequest(AuthConfig config) {
|
||||||
super(config, AuthSource.GITHUB);
|
super(config, AuthSource.GITHUB);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthToken getAccessToken(String code) {
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
String accessTokenUrl = UrlBuilder.getGithubAccessTokenUrl(config.getClientId(), config.getClientSecret(), code, config.getRedirectUri());
|
HttpResponse response = doPostAuthorizationCode(authCallback.getCode());
|
||||||
HttpResponse response = HttpRequest.post(accessTokenUrl).execute();
|
|
||||||
Map<String, String> res = GlobalAuthUtil.parseStringToMap(response.body());
|
Map<String, String> res = GlobalAuthUtil.parseStringToMap(response.body());
|
||||||
if (res.containsKey("error")) {
|
if (res.containsKey("error")) {
|
||||||
throw new AuthException(res.get("error") + ":" + res.get("error_description"));
|
throw new AuthException(res.get("error") + ":" + res.get("error_description"));
|
||||||
}
|
}
|
||||||
return AuthToken.builder()
|
return AuthToken.builder()
|
||||||
.accessToken(res.get("access_token"))
|
.accessToken(res.get("access_token"))
|
||||||
.build();
|
.scope(res.get("scope"))
|
||||||
|
.tokenType(res.get("token_type"))
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
String accessToken = authToken.getAccessToken();
|
HttpResponse response = doGetUserInfo(authToken);
|
||||||
HttpResponse response = HttpRequest.get(UrlBuilder.getGithubUserInfoUrl(accessToken)).execute();
|
JSONObject object = JSONObject.parseObject(response.body());
|
||||||
String userInfo = response.body();
|
if (object.containsKey("error")) {
|
||||||
JSONObject object = JSONObject.parseObject(userInfo);
|
throw new AuthException(object.getString("error_description"));
|
||||||
|
}
|
||||||
return AuthUser.builder()
|
return AuthUser.builder()
|
||||||
.uuid(object.getString("id"))
|
.uuid(object.getString("id"))
|
||||||
.username(object.getString("login"))
|
.username(object.getString("login"))
|
||||||
.avatar(object.getString("avatar_url"))
|
.avatar(object.getString("avatar_url"))
|
||||||
.blog(object.getString("blog"))
|
.blog(object.getString("blog"))
|
||||||
.nickname(object.getString("name"))
|
.nickname(object.getString("name"))
|
||||||
.company(object.getString("company"))
|
.company(object.getString("company"))
|
||||||
.location(object.getString("location"))
|
.location(object.getString("location"))
|
||||||
.email(object.getString("email"))
|
.email(object.getString("email"))
|
||||||
.remark(object.getString("bio"))
|
.remark(object.getString("bio"))
|
||||||
.token(authToken)
|
.gender(AuthUserGender.UNKNOWN)
|
||||||
.source(AuthSource.GITHUB)
|
.token(authToken)
|
||||||
.build();
|
.source(source)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查响应内容是否正确
|
||||||
|
*
|
||||||
|
* @param object 请求响应内容
|
||||||
|
*/
|
||||||
|
private void checkResponse(JSONObject object) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ import cn.hutool.http.HttpRequest;
|
|||||||
import cn.hutool.http.HttpResponse;
|
import cn.hutool.http.HttpResponse;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
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.exception.AuthException;
|
||||||
import me.zhyd.oauth.model.AuthSource;
|
import me.zhyd.oauth.model.AuthCallback;
|
||||||
import me.zhyd.oauth.model.AuthToken;
|
import me.zhyd.oauth.model.AuthToken;
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
@@ -17,48 +19,83 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* @version 1.3
|
* @version 1.3
|
||||||
* @since 1.3
|
* @since 1.3
|
||||||
*/
|
*/
|
||||||
public class AuthGoogleRequest extends BaseAuthRequest {
|
public class AuthGoogleRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
public AuthGoogleRequest(AuthConfig config) {
|
public AuthGoogleRequest(AuthConfig config) {
|
||||||
super(config, AuthSource.GOOGLE);
|
super(config, AuthSource.GOOGLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthToken getAccessToken(String code) {
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
String accessTokenUrl = UrlBuilder.getGoogleAccessTokenUrl(config.getClientId(), config.getClientSecret(), code, config
|
HttpResponse response = doPostAuthorizationCode(authCallback.getCode());
|
||||||
.getRedirectUri());
|
JSONObject accessTokenObject = JSONObject.parseObject(response.body());
|
||||||
HttpResponse response = HttpRequest.post(accessTokenUrl).execute();
|
this.checkResponse(accessTokenObject);
|
||||||
JSONObject object = JSONObject.parseObject(response.body());
|
|
||||||
|
|
||||||
if (object.containsKey("error") || object.containsKey("error_description")) {
|
|
||||||
throw new AuthException("get google access_token has error:[" + object.getString("error") + "], error_description:[" + object
|
|
||||||
.getString("error_description") + "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
return AuthToken.builder()
|
return AuthToken.builder()
|
||||||
.accessToken(object.getString("access_token"))
|
.accessToken(accessTokenObject.getString("access_token"))
|
||||||
.expireIn(object.getIntValue("expires_in"))
|
.expireIn(accessTokenObject.getIntValue("expires_in"))
|
||||||
.scope(object.getString("scope"))
|
.scope(accessTokenObject.getString("scope"))
|
||||||
.tokenType(object.getString("token_type"))
|
.tokenType(accessTokenObject.getString("token_type"))
|
||||||
.idToken(object.getString("id_token"))
|
.idToken(accessTokenObject.getString("id_token"))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
String accessToken = authToken.getIdToken();
|
HttpResponse response = HttpRequest.post(userInfoUrl(authToken))
|
||||||
HttpResponse response = HttpRequest.get(UrlBuilder.getGoogleUserInfoUrl(accessToken)).execute();
|
.header("Authorization", "Bearer " + authToken.getAccessToken())
|
||||||
|
.execute();
|
||||||
String userInfo = response.body();
|
String userInfo = response.body();
|
||||||
JSONObject object = JSONObject.parseObject(userInfo);
|
JSONObject object = JSONObject.parseObject(userInfo);
|
||||||
|
this.checkResponse(object);
|
||||||
return AuthUser.builder()
|
return AuthUser.builder()
|
||||||
.uuid(object.getString("sub"))
|
.uuid(object.getString("sub"))
|
||||||
.username(object.getString("name"))
|
.username(object.getString("email"))
|
||||||
.avatar(object.getString("picture"))
|
.avatar(object.getString("picture"))
|
||||||
.nickname(object.getString("name"))
|
.nickname(object.getString("name"))
|
||||||
.location(object.getString("locale"))
|
.location(object.getString("locale"))
|
||||||
.email(object.getString("email"))
|
.email(object.getString("email"))
|
||||||
.token(authToken)
|
.gender(AuthUserGender.UNKNOWN)
|
||||||
.source(AuthSource.GOOGLE)
|
.token(authToken)
|
||||||
.build();
|
.source(source)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回认证url,可自行跳转页面
|
||||||
|
* https://openidconnect.googleapis.com/v1/userinfo
|
||||||
|
*
|
||||||
|
* @return 返回授权地址
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
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()))
|
||||||
|
.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()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查响应内容是否正确
|
||||||
|
*
|
||||||
|
* @param object 请求响应内容
|
||||||
|
*/
|
||||||
|
private void checkResponse(JSONObject object) {
|
||||||
|
if (object.containsKey("error") || object.containsKey("error_description")) {
|
||||||
|
throw new AuthException(object.containsKey("error") + ":" + object.getString("error_description"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,212 @@
|
|||||||
|
package me.zhyd.oauth.request;
|
||||||
|
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.alibaba.fastjson.JSONPath;
|
||||||
|
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.*;
|
||||||
|
import me.zhyd.oauth.utils.StringUtils;
|
||||||
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 领英登录
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.8
|
||||||
|
*/
|
||||||
|
public class AuthLinkedinRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
|
public AuthLinkedinRequest(AuthConfig config) {
|
||||||
|
super(config, AuthSource.LINKEDIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
|
return this.getToken(accessTokenUrl(authCallback.getCode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
|
String accessToken = authToken.getAccessToken();
|
||||||
|
HttpResponse response = HttpRequest.get(userInfoUrl(authToken))
|
||||||
|
.header("Host", "api.linkedin.com")
|
||||||
|
.header("Connection", "Keep-Alive")
|
||||||
|
.header("Authorization", "Bearer " + accessToken)
|
||||||
|
.execute();
|
||||||
|
JSONObject userInfoObject = JSONObject.parseObject(response.body());
|
||||||
|
|
||||||
|
this.checkResponse(userInfoObject);
|
||||||
|
|
||||||
|
String userName = getUserName(userInfoObject);
|
||||||
|
|
||||||
|
// 获取用户头像
|
||||||
|
String avatar = this.getAvatar(userInfoObject);
|
||||||
|
|
||||||
|
// 获取用户邮箱地址
|
||||||
|
String email = this.getUserEmail(accessToken);
|
||||||
|
return AuthUser.builder()
|
||||||
|
.uuid(userInfoObject.getString("id"))
|
||||||
|
.username(userName)
|
||||||
|
.nickname(userName)
|
||||||
|
.avatar(avatar)
|
||||||
|
.email(email)
|
||||||
|
.token(authToken)
|
||||||
|
.gender(AuthUserGender.UNKNOWN)
|
||||||
|
.source(AuthSource.LINKEDIN)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户的真实名
|
||||||
|
*
|
||||||
|
* @param userInfoObject 用户json对象
|
||||||
|
* @return 用户名
|
||||||
|
*/
|
||||||
|
private String getUserName(JSONObject userInfoObject) {
|
||||||
|
String firstName, lastName;
|
||||||
|
// 获取firstName
|
||||||
|
if (userInfoObject.containsKey("localizedFirstName")) {
|
||||||
|
firstName = userInfoObject.getString("localizedFirstName");
|
||||||
|
} else {
|
||||||
|
firstName = getUserName(userInfoObject, "firstName");
|
||||||
|
}
|
||||||
|
// 获取lastName
|
||||||
|
if (userInfoObject.containsKey("localizedLastName")) {
|
||||||
|
lastName = userInfoObject.getString("localizedLastName");
|
||||||
|
} else {
|
||||||
|
lastName = getUserName(userInfoObject, "lastName");
|
||||||
|
}
|
||||||
|
return firstName + " " + lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户的头像
|
||||||
|
*
|
||||||
|
* @param userInfoObject 用户json对象
|
||||||
|
* @return 用户的头像地址
|
||||||
|
*/
|
||||||
|
private String getAvatar(JSONObject userInfoObject) {
|
||||||
|
String avatar = null;
|
||||||
|
JSONObject profilePictureObject = userInfoObject.getJSONObject("profilePicture");
|
||||||
|
if (profilePictureObject.containsKey("displayImage~")) {
|
||||||
|
JSONArray displayImageElements = profilePictureObject.getJSONObject("displayImage~")
|
||||||
|
.getJSONArray("elements");
|
||||||
|
if (null != displayImageElements && displayImageElements.size() > 0) {
|
||||||
|
JSONObject largestImageObj = displayImageElements.getJSONObject(displayImageElements.size() - 1);
|
||||||
|
avatar = largestImageObj.getJSONArray("identifiers").getJSONObject(0).getString("identifier");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return avatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户的email
|
||||||
|
*
|
||||||
|
* @param accessToken 用户授权后返回的token
|
||||||
|
* @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")
|
||||||
|
.header("Authorization", "Bearer " + accessToken)
|
||||||
|
.execute();
|
||||||
|
JSONObject emailObj = JSONObject.parseObject(emailResponse.body());
|
||||||
|
this.checkResponse(emailObj);
|
||||||
|
Object obj = JSONPath.eval(emailObj, "$['elements'][0]['handle~']['emailAddress']");
|
||||||
|
return null == obj ? null : (String) obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getUserName(JSONObject userInfoObject, String nameKey) {
|
||||||
|
String firstName;
|
||||||
|
JSONObject firstNameObj = userInfoObject.getJSONObject(nameKey);
|
||||||
|
JSONObject localizedObj = firstNameObj.getJSONObject("localized");
|
||||||
|
JSONObject preferredLocaleObj = firstNameObj.getJSONObject("preferredLocale");
|
||||||
|
firstName = localizedObj.getString(preferredLocaleObj.getString("language") + "_" + preferredLocaleObj.getString("country"));
|
||||||
|
return firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthResponse refresh(AuthToken oldToken) {
|
||||||
|
String refreshToken = oldToken.getRefreshToken();
|
||||||
|
if (StringUtils.isEmpty(refreshToken)) {
|
||||||
|
throw new AuthException(AuthResponseStatus.UNSUPPORTED);
|
||||||
|
}
|
||||||
|
String refreshTokenUrl = refreshTokenUrl(refreshToken);
|
||||||
|
return AuthResponse.builder()
|
||||||
|
.code(AuthResponseStatus.SUCCESS.getCode())
|
||||||
|
.data(this.getToken(refreshTokenUrl))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查响应内容是否正确
|
||||||
|
*
|
||||||
|
* @param object 请求响应内容
|
||||||
|
*/
|
||||||
|
private void checkResponse(JSONObject object) {
|
||||||
|
if (object.containsKey("error")) {
|
||||||
|
throw new AuthException(object.getString("error_description"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取token,适用于获取access_token和刷新token
|
||||||
|
*
|
||||||
|
* @param accessTokenUrl 实际请求token的地址
|
||||||
|
* @return token对象
|
||||||
|
*/
|
||||||
|
private AuthToken getToken(String accessTokenUrl) {
|
||||||
|
HttpResponse response = HttpRequest.post(accessTokenUrl)
|
||||||
|
.header("Host", "www.linkedin.com")
|
||||||
|
.contentType("application/x-www-form-urlencoded")
|
||||||
|
.execute();
|
||||||
|
String accessTokenStr = response.body();
|
||||||
|
JSONObject accessTokenObject = JSONObject.parseObject(accessTokenStr);
|
||||||
|
|
||||||
|
this.checkResponse(accessTokenObject);
|
||||||
|
|
||||||
|
return AuthToken.builder()
|
||||||
|
.accessToken(accessTokenObject.getString("access_token"))
|
||||||
|
.expireIn(accessTokenObject.getIntValue("expires_in"))
|
||||||
|
.refreshToken(accessTokenObject.getString("refresh_token"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回认证url,可自行跳转页面
|
||||||
|
*
|
||||||
|
* @return 返回授权地址
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
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")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取userInfo的url
|
||||||
|
*
|
||||||
|
* @param authToken 用户授权后的token
|
||||||
|
* @return 返回获取userInfo的url
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String userInfoUrl(AuthToken authToken) {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.userInfo())
|
||||||
|
.queryParam("projection", "(id,firstName,lastName,profilePicture(displayImage~:playableStreams))")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
package me.zhyd.oauth.request;
|
||||||
|
|
||||||
|
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.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.*;
|
||||||
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 小米登录
|
||||||
|
*
|
||||||
|
* @author yangkai.shen (https://xkcoding.com)
|
||||||
|
* @version 1.5
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class AuthMiRequest extends AuthDefaultRequest {
|
||||||
|
private static final String PREFIX = "&&&START&&&";
|
||||||
|
|
||||||
|
public AuthMiRequest(AuthConfig config) {
|
||||||
|
super(config, AuthSource.MI);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
|
return getToken(accessTokenUrl(authCallback.getCode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuthToken getToken(String accessTokenUrl) {
|
||||||
|
HttpResponse response = HttpRequest.get(accessTokenUrl).execute();
|
||||||
|
String jsonStr = StrUtil.replace(response.body(), PREFIX, StrUtil.EMPTY);
|
||||||
|
JSONObject accessTokenObject = JSONObject.parseObject(jsonStr);
|
||||||
|
|
||||||
|
if (accessTokenObject.containsKey("error")) {
|
||||||
|
throw new AuthException(accessTokenObject.getString("error_description"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return AuthToken.builder()
|
||||||
|
.accessToken(accessTokenObject.getString("access_token"))
|
||||||
|
.expireIn(accessTokenObject.getIntValue("expires_in"))
|
||||||
|
.scope(accessTokenObject.getString("scope"))
|
||||||
|
.tokenType(accessTokenObject.getString("token_type"))
|
||||||
|
.refreshToken(accessTokenObject.getString("refresh_token"))
|
||||||
|
.openId(accessTokenObject.getString("openId"))
|
||||||
|
.macAlgorithm(accessTokenObject.getString("mac_algorithm"))
|
||||||
|
.macKey(accessTokenObject.getString("mac_key"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
|
// 获取用户信息
|
||||||
|
HttpResponse userResponse = doGetUserInfo(authToken);
|
||||||
|
|
||||||
|
JSONObject userProfile = JSONObject.parseObject(userResponse.body());
|
||||||
|
if ("error".equalsIgnoreCase(userProfile.getString("result"))) {
|
||||||
|
throw new AuthException(userProfile.getString("description"));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject user = userProfile.getJSONObject("data");
|
||||||
|
|
||||||
|
AuthUser authUser = AuthUser.builder()
|
||||||
|
.uuid(authToken.getOpenId())
|
||||||
|
.username(user.getString("miliaoNick"))
|
||||||
|
.nickname(user.getString("miliaoNick"))
|
||||||
|
.avatar(user.getString("miliaoIcon"))
|
||||||
|
.email(user.getString("mail"))
|
||||||
|
.gender(AuthUserGender.UNKNOWN)
|
||||||
|
.token(authToken)
|
||||||
|
.source(source)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 获取用户邮箱手机号等信息
|
||||||
|
String emailPhoneUrl = MessageFormat.format("{0}?clientId={1}&token={2}", "https://open.account.xiaomi.com/user/phoneAndEmail", config
|
||||||
|
.getClientId(), authToken.getAccessToken());
|
||||||
|
|
||||||
|
HttpResponse emailResponse = HttpRequest.get(emailPhoneUrl).execute();
|
||||||
|
JSONObject userEmailPhone = JSONObject.parseObject(emailResponse.body());
|
||||||
|
if (!"error".equalsIgnoreCase(userEmailPhone.getString("result"))) {
|
||||||
|
JSONObject emailPhone = userEmailPhone.getJSONObject("data");
|
||||||
|
authUser.setEmail(emailPhone.getString("email"));
|
||||||
|
} else {
|
||||||
|
log.warn("小米开发平台暂时不对外开放用户手机及邮箱信息的获取");
|
||||||
|
}
|
||||||
|
|
||||||
|
return authUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新access token (续期)
|
||||||
|
*
|
||||||
|
* @param authToken 登录成功后返回的Token信息
|
||||||
|
* @return AuthResponse
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public AuthResponse refresh(AuthToken authToken) {
|
||||||
|
return AuthResponse.builder()
|
||||||
|
.code(AuthResponseStatus.SUCCESS.getCode())
|
||||||
|
.data(getToken(refreshTokenUrl(authToken.getRefreshToken())))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回认证url,可自行跳转页面
|
||||||
|
*
|
||||||
|
* @return 返回授权地址
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
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")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取userInfo的url
|
||||||
|
*
|
||||||
|
* @param authToken 用户授权后的token
|
||||||
|
* @return 返回获取userInfo的url
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String userInfoUrl(AuthToken authToken) {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.userInfo())
|
||||||
|
.queryParam("clientId", config.getClientId())
|
||||||
|
.queryParam("token", authToken.getAccessToken())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
package me.zhyd.oauth.request;
|
||||||
|
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
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.*;
|
||||||
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
|
|
||||||
|
import static me.zhyd.oauth.utils.GlobalAuthUtil.parseQueryToMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微软登录
|
||||||
|
*
|
||||||
|
* @author yangkai.shen (https://xkcoding.com)
|
||||||
|
* @version 1.5
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
public class AuthMicrosoftRequest extends AuthDefaultRequest {
|
||||||
|
public AuthMicrosoftRequest(AuthConfig config) {
|
||||||
|
super(config, AuthSource.MICROSOFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
|
return getToken(accessTokenUrl(authCallback.getCode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取token,适用于获取access_token和刷新token
|
||||||
|
*
|
||||||
|
* @param accessTokenUrl 实际请求token的地址
|
||||||
|
* @return token对象
|
||||||
|
*/
|
||||||
|
private AuthToken getToken(String accessTokenUrl) {
|
||||||
|
HttpResponse response = HttpRequest.post(accessTokenUrl)
|
||||||
|
.header("Host", "https://login.microsoftonline.com")
|
||||||
|
.contentType("application/x-www-form-urlencoded")
|
||||||
|
.form(parseQueryToMap(accessTokenUrl))
|
||||||
|
.execute();
|
||||||
|
String accessTokenStr = response.body();
|
||||||
|
JSONObject accessTokenObject = JSONObject.parseObject(accessTokenStr);
|
||||||
|
|
||||||
|
this.checkResponse(accessTokenObject);
|
||||||
|
|
||||||
|
return AuthToken.builder()
|
||||||
|
.accessToken(accessTokenObject.getString("access_token"))
|
||||||
|
.expireIn(accessTokenObject.getIntValue("expires_in"))
|
||||||
|
.scope(accessTokenObject.getString("scope"))
|
||||||
|
.tokenType(accessTokenObject.getString("token_type"))
|
||||||
|
.refreshToken(accessTokenObject.getString("refresh_token"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查响应内容是否正确
|
||||||
|
*
|
||||||
|
* @param object 请求响应内容
|
||||||
|
*/
|
||||||
|
private void checkResponse(JSONObject object) {
|
||||||
|
if (object.containsKey("error")) {
|
||||||
|
throw new AuthException(object.getString("error_description"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
|
String token = authToken.getAccessToken();
|
||||||
|
String tokenType = authToken.getTokenType();
|
||||||
|
String jwt = tokenType + " " + token;
|
||||||
|
HttpResponse response = HttpRequest.get(userInfoUrl(authToken)).header("Authorization", jwt).execute();
|
||||||
|
String userInfo = response.body();
|
||||||
|
JSONObject object = JSONObject.parseObject(userInfo);
|
||||||
|
this.checkResponse(object);
|
||||||
|
return AuthUser.builder()
|
||||||
|
.uuid(object.getString("id"))
|
||||||
|
.username(object.getString("userPrincipalName"))
|
||||||
|
.nickname(object.getString("displayName"))
|
||||||
|
.location(object.getString("officeLocation"))
|
||||||
|
.email(object.getString("mail"))
|
||||||
|
.gender(AuthUserGender.UNKNOWN)
|
||||||
|
.token(authToken)
|
||||||
|
.source(source)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新access token (续期)
|
||||||
|
*
|
||||||
|
* @param authToken 登录成功后返回的Token信息
|
||||||
|
* @return AuthResponse
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public AuthResponse refresh(AuthToken authToken) {
|
||||||
|
return AuthResponse.builder()
|
||||||
|
.code(AuthResponseStatus.SUCCESS.getCode())
|
||||||
|
.data(getToken(refreshTokenUrl(authToken.getRefreshToken())))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回认证url,可自行跳转页面
|
||||||
|
*
|
||||||
|
* @return 返回授权地址
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
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()))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取accessToken的url
|
||||||
|
*
|
||||||
|
* @param code
|
||||||
|
* @return 返回获取accessToken的url
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String accessTokenUrl(String code) {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.accessToken())
|
||||||
|
.queryParam("code", code)
|
||||||
|
.queryParam("client_id", config.getClientId())
|
||||||
|
.queryParam("client_secret", config.getClientSecret())
|
||||||
|
.queryParam("grant_type", "authorization_code")
|
||||||
|
.queryParam("scope", "user.read%20mail.read")
|
||||||
|
.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()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取accessToken的url
|
||||||
|
*
|
||||||
|
* @param refreshToken 用户授权后的token
|
||||||
|
* @return 返回获取accessToken的url
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String refreshTokenUrl(String refreshToken) {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.refresh())
|
||||||
|
.queryParam("client_id", config.getClientId())
|
||||||
|
.queryParam("client_secret", config.getClientSecret())
|
||||||
|
.queryParam("refresh_token", refreshToken)
|
||||||
|
.queryParam("grant_type", "refresh_token")
|
||||||
|
.queryParam("scope", "user.read%20mail.read")
|
||||||
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
package me.zhyd.oauth.request;
|
package me.zhyd.oauth.request;
|
||||||
|
|
||||||
import cn.hutool.http.HttpRequest;
|
|
||||||
import cn.hutool.http.HttpResponse;
|
import cn.hutool.http.HttpResponse;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
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.exception.AuthException;
|
||||||
import me.zhyd.oauth.model.AuthSource;
|
import me.zhyd.oauth.model.AuthCallback;
|
||||||
import me.zhyd.oauth.model.AuthToken;
|
import me.zhyd.oauth.model.AuthToken;
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
import me.zhyd.oauth.model.AuthUserGender;
|
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,44 +18,84 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
public class AuthOschinaRequest extends BaseAuthRequest {
|
public class AuthOschinaRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
public AuthOschinaRequest(AuthConfig config) {
|
public AuthOschinaRequest(AuthConfig config) {
|
||||||
super(config, AuthSource.OSCHINA);
|
super(config, AuthSource.OSCHINA);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthToken getAccessToken(String code) {
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
String accessTokenUrl = UrlBuilder.getOschinaAccessTokenUrl(config.getClientId(), config.getClientSecret(), code, config.getRedirectUri());
|
HttpResponse response = doPostAuthorizationCode(authCallback.getCode());
|
||||||
HttpResponse response = HttpRequest.post(accessTokenUrl).execute();
|
|
||||||
JSONObject accessTokenObject = JSONObject.parseObject(response.body());
|
JSONObject accessTokenObject = JSONObject.parseObject(response.body());
|
||||||
if (accessTokenObject.containsKey("error")) {
|
this.checkResponse(accessTokenObject);
|
||||||
throw new AuthException("Unable to get token from oschina using code [" + code + "]");
|
|
||||||
}
|
|
||||||
return AuthToken.builder()
|
return AuthToken.builder()
|
||||||
.accessToken(accessTokenObject.getString("access_token"))
|
.accessToken(accessTokenObject.getString("access_token"))
|
||||||
.build();
|
.refreshToken(accessTokenObject.getString("refresh_token"))
|
||||||
|
.uid(accessTokenObject.getString("uid"))
|
||||||
|
.expireIn(accessTokenObject.getIntValue("expires_in"))
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
String accessToken = authToken.getAccessToken();
|
HttpResponse response = doGetUserInfo(authToken);
|
||||||
HttpResponse response = HttpRequest.get(UrlBuilder.getOschinaUserInfoUrl(accessToken)).execute();
|
|
||||||
JSONObject object = JSONObject.parseObject(response.body());
|
JSONObject object = JSONObject.parseObject(response.body());
|
||||||
|
this.checkResponse(object);
|
||||||
|
return AuthUser.builder()
|
||||||
|
.uuid(object.getString("id"))
|
||||||
|
.username(object.getString("name"))
|
||||||
|
.nickname(object.getString("name"))
|
||||||
|
.avatar(object.getString("avatar"))
|
||||||
|
.blog(object.getString("url"))
|
||||||
|
.location(object.getString("location"))
|
||||||
|
.gender(AuthUserGender.getRealGender(object.getString("gender")))
|
||||||
|
.email(object.getString("email"))
|
||||||
|
.token(authToken)
|
||||||
|
.source(source)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取accessToken的url
|
||||||
|
*
|
||||||
|
* @param code
|
||||||
|
* @return 返回获取accessToken的url
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String accessTokenUrl(String code) {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.accessToken())
|
||||||
|
.queryParam("code", code)
|
||||||
|
.queryParam("client_id", config.getClientId())
|
||||||
|
.queryParam("client_secret", config.getClientSecret())
|
||||||
|
.queryParam("grant_type", "authorization_code")
|
||||||
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
|
.queryParam("dataType", "json")
|
||||||
|
.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("dataType", "json")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查响应内容是否正确
|
||||||
|
*
|
||||||
|
* @param object 请求响应内容
|
||||||
|
*/
|
||||||
|
private void checkResponse(JSONObject object) {
|
||||||
if (object.containsKey("error")) {
|
if (object.containsKey("error")) {
|
||||||
throw new AuthException(object.getString("error_description"));
|
throw new AuthException(object.getString("error_description"));
|
||||||
}
|
}
|
||||||
return AuthUser.builder()
|
|
||||||
.uuid(object.getString("id"))
|
|
||||||
.username(object.getString("name"))
|
|
||||||
.nickname(object.getString("name"))
|
|
||||||
.avatar(object.getString("avatar"))
|
|
||||||
.blog(object.getString("url"))
|
|
||||||
.location(object.getString("location"))
|
|
||||||
.gender(AuthUserGender.getRealGender(object.getString("gender")))
|
|
||||||
.email(object.getString("email"))
|
|
||||||
.token(authToken)
|
|
||||||
.source(AuthSource.OSCHINA)
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
package me.zhyd.oauth.request;
|
||||||
|
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import me.zhyd.oauth.config.AuthConfig;
|
||||||
|
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;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static me.zhyd.oauth.config.AuthSource.PINTEREST;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pinterest登录
|
||||||
|
*
|
||||||
|
* @author hongwei.peng (pengisgood(at)gmail(dot)com)
|
||||||
|
* @version 1.9.0
|
||||||
|
* @since 1.8
|
||||||
|
*/
|
||||||
|
public class AuthPinterestRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
|
private static final String FAILURE = "failure";
|
||||||
|
|
||||||
|
public AuthPinterestRequest(AuthConfig config) {
|
||||||
|
super(config, PINTEREST);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
|
HttpResponse response = doPostAuthorizationCode(authCallback.getCode());
|
||||||
|
JSONObject accessTokenObject = JSONObject.parseObject(response.body());
|
||||||
|
this.checkResponse(accessTokenObject);
|
||||||
|
return AuthToken.builder()
|
||||||
|
.accessToken(accessTokenObject.getString("access_token"))
|
||||||
|
.tokenType(accessTokenObject.getString("token_type"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
|
String userinfoUrl = userInfoUrl(authToken);
|
||||||
|
HttpResponse response = HttpRequest.get(userinfoUrl).setFollowRedirects(true).execute();
|
||||||
|
JSONObject object = JSONObject.parseObject(response.body());
|
||||||
|
this.checkResponse(object);
|
||||||
|
JSONObject userObj = object.getJSONObject("data");
|
||||||
|
return AuthUser.builder()
|
||||||
|
.uuid(userObj.getString("id"))
|
||||||
|
.avatar(getAvatarUrl(userObj))
|
||||||
|
.username(userObj.getString("username"))
|
||||||
|
.nickname(userObj.getString("first_name") + " " + userObj.getString("last_name"))
|
||||||
|
.gender(AuthUserGender.UNKNOWN)
|
||||||
|
.remark(userObj.getString("bio"))
|
||||||
|
.token(authToken)
|
||||||
|
.source(source)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getAvatarUrl(JSONObject userObj) {
|
||||||
|
// image is a map data structure
|
||||||
|
JSONObject jsonObject = userObj.getJSONObject("image");
|
||||||
|
if (Objects.isNull(jsonObject)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return jsonObject.getJSONObject("60x60").getString("url");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
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")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取userInfo的url
|
||||||
|
*
|
||||||
|
* @param authToken token
|
||||||
|
* @return 返回获取userInfo的url
|
||||||
|
*/
|
||||||
|
protected String userInfoUrl(AuthToken authToken) {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.userInfo())
|
||||||
|
.queryParam("access_token", authToken.getAccessToken())
|
||||||
|
.queryParam("fields", "id,username,first_name,last_name,bio,image")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查响应内容是否正确
|
||||||
|
*
|
||||||
|
* @param object 请求响应内容
|
||||||
|
*/
|
||||||
|
private void checkResponse(JSONObject object) {
|
||||||
|
if (!object.containsKey("status") && FAILURE.equals(object.getString("status"))) {
|
||||||
|
throw new AuthException(object.getString("message"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,11 +5,10 @@ import cn.hutool.http.HttpRequest;
|
|||||||
import cn.hutool.http.HttpResponse;
|
import cn.hutool.http.HttpResponse;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
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.exception.AuthException;
|
||||||
import me.zhyd.oauth.model.AuthSource;
|
import me.zhyd.oauth.model.*;
|
||||||
import me.zhyd.oauth.model.AuthToken;
|
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
|
||||||
import me.zhyd.oauth.model.AuthUserGender;
|
|
||||||
import me.zhyd.oauth.utils.GlobalAuthUtil;
|
import me.zhyd.oauth.utils.GlobalAuthUtil;
|
||||||
import me.zhyd.oauth.utils.StringUtils;
|
import me.zhyd.oauth.utils.StringUtils;
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
@@ -24,33 +23,30 @@ import java.util.Map;
|
|||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
public class AuthQqRequest extends BaseAuthRequest {
|
public class AuthQqRequest extends AuthDefaultRequest {
|
||||||
public AuthQqRequest(AuthConfig config) {
|
public AuthQqRequest(AuthConfig config) {
|
||||||
super(config, AuthSource.QQ);
|
super(config, AuthSource.QQ);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthToken getAccessToken(String code) {
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
String accessTokenUrl = UrlBuilder.getQqAccessTokenUrl(config.getClientId(), config.getClientSecret(), code, config
|
HttpResponse response = doGetAuthorizationCode(authCallback.getCode());
|
||||||
.getRedirectUri());
|
return getAuthToken(response);
|
||||||
HttpResponse response = HttpRequest.get(accessTokenUrl).execute();
|
}
|
||||||
Map<String, String> accessTokenObject = GlobalAuthUtil.parseStringToMap(response.body());
|
|
||||||
if (!accessTokenObject.containsKey("access_token")) {
|
@Override
|
||||||
throw new AuthException("Unable to get token from qq using code [" + code + "]");
|
public AuthResponse refresh(AuthToken authToken) {
|
||||||
}
|
HttpResponse response = HttpRequest.get(refreshTokenUrl(authToken.getRefreshToken())).execute();
|
||||||
return AuthToken.builder()
|
return AuthResponse.builder()
|
||||||
.accessToken(accessTokenObject.get("access_token"))
|
.code(AuthResponseStatus.SUCCESS.getCode())
|
||||||
.expireIn(Integer.valueOf(accessTokenObject.get("expires_in")))
|
.data(getAuthToken(response))
|
||||||
.refreshToken(accessTokenObject.get("refresh_token"))
|
.build();
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
String accessToken = authToken.getAccessToken();
|
String openId = this.getOpenId(authToken);
|
||||||
String openId = this.getOpenId(accessToken);
|
HttpResponse response = doGetUserInfo(authToken);
|
||||||
HttpResponse response = HttpRequest.get(UrlBuilder.getQqUserInfoUrl(config.getClientId(), accessToken, openId))
|
|
||||||
.execute();
|
|
||||||
JSONObject object = JSONObject.parseObject(response.body());
|
JSONObject object = JSONObject.parseObject(response.body());
|
||||||
if (object.getIntValue("ret") != 0) {
|
if (object.getIntValue("ret") != 0) {
|
||||||
throw new AuthException(object.getString("msg"));
|
throw new AuthException(object.getString("msg"));
|
||||||
@@ -59,32 +55,68 @@ public class AuthQqRequest extends BaseAuthRequest {
|
|||||||
if (StringUtils.isEmpty(avatar)) {
|
if (StringUtils.isEmpty(avatar)) {
|
||||||
avatar = object.getString("figureurl_qq_1");
|
avatar = object.getString("figureurl_qq_1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String location = String.format("%s-%s", object.getString("province"), object.getString("city"));
|
||||||
return AuthUser.builder()
|
return AuthUser.builder()
|
||||||
.username(object.getString("nickname"))
|
.username(object.getString("nickname"))
|
||||||
.nickname(object.getString("nickname"))
|
.nickname(object.getString("nickname"))
|
||||||
.avatar(avatar)
|
.avatar(avatar)
|
||||||
.location(object.getString("province") + "-" + object.getString("city"))
|
.location(location)
|
||||||
.uuid(openId)
|
.uuid(openId)
|
||||||
.gender(AuthUserGender.getRealGender(object.getString("gender")))
|
.gender(AuthUserGender.getRealGender(object.getString("gender")))
|
||||||
.token(authToken)
|
.token(authToken)
|
||||||
.source(AuthSource.QQ)
|
.source(source)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getOpenId(String accessToken) {
|
private String getOpenId(AuthToken authToken) {
|
||||||
HttpResponse response = HttpRequest.get(UrlBuilder.getQqOpenidUrl("https://graph.qq.com/oauth2.0/me", accessToken))
|
HttpResponse response = HttpRequest.get(UrlBuilder.fromBaseUrl("https://graph.qq.com/oauth2.0/me")
|
||||||
.execute();
|
.queryParam("access_token", authToken.getAccessToken())
|
||||||
|
.queryParam("unionid", config.isUnionId() ? 1 : 0)
|
||||||
|
.build()).execute();
|
||||||
if (response.isOk()) {
|
if (response.isOk()) {
|
||||||
String body = response.body();
|
String body = response.body();
|
||||||
String removePrefix = StrUtil.replace(body, "callback(", "");
|
String removePrefix = StrUtil.replace(body, "callback(", "");
|
||||||
String removeSuffix = StrUtil.replace(removePrefix, ");", "");
|
String removeSuffix = StrUtil.replace(removePrefix, ");", "");
|
||||||
String openId = StrUtil.trim(removeSuffix);
|
String openId = StrUtil.trim(removeSuffix);
|
||||||
JSONObject object = JSONObject.parseObject(openId);
|
JSONObject object = JSONObject.parseObject(openId);
|
||||||
if (object.containsKey("openid")) {
|
if (object.containsKey("error")) {
|
||||||
return object.getString("openid");
|
throw new AuthException(object.get("error") + ":" + object.get("error_description"));
|
||||||
}
|
}
|
||||||
throw new AuthException("Invalid openId");
|
authToken.setOpenId(object.getString("openid"));
|
||||||
|
if (object.containsKey("unionid")) {
|
||||||
|
authToken.setUnionId(object.getString("unionid"));
|
||||||
|
}
|
||||||
|
return StringUtils.isEmpty(authToken.getUnionId()) ? authToken.getOpenId() : authToken.getUnionId();
|
||||||
}
|
}
|
||||||
throw new AuthException("Invalid openId");
|
|
||||||
|
throw new AuthException("request error");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取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("oauth_consumer_key", config.getClientId())
|
||||||
|
.queryParam("openid", authToken.getOpenId())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuthToken getAuthToken(HttpResponse response) {
|
||||||
|
Map<String, String> accessTokenObject = GlobalAuthUtil.parseStringToMap(response.body());
|
||||||
|
if (!accessTokenObject.containsKey("access_token") || accessTokenObject.containsKey("code")) {
|
||||||
|
throw new AuthException(accessTokenObject.get("msg"));
|
||||||
|
}
|
||||||
|
return AuthToken.builder()
|
||||||
|
.accessToken(accessTokenObject.get("access_token"))
|
||||||
|
.expireIn(Integer.valueOf(accessTokenObject.get("expires_in")))
|
||||||
|
.refreshToken(accessTokenObject.get("refresh_token"))
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
package me.zhyd.oauth.request;
|
||||||
|
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
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.utils.UrlBuilder;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static me.zhyd.oauth.config.AuthSource.RENREN;
|
||||||
|
import static me.zhyd.oauth.model.AuthResponseStatus.SUCCESS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人人登录
|
||||||
|
*
|
||||||
|
* @author hongwei.peng (pengisgood(at)gmail(dot)com)
|
||||||
|
* @version 1.9.0
|
||||||
|
* @since 1.8
|
||||||
|
*/
|
||||||
|
public class AuthRenrenRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
|
public AuthRenrenRequest(AuthConfig config) {
|
||||||
|
super(config, RENREN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
|
return this.getToken(accessTokenUrl(authCallback.getCode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
|
HttpResponse response = doGetUserInfo(authToken);
|
||||||
|
JSONObject userObj = JSONObject.parseObject(response.body()).getJSONObject("response");
|
||||||
|
|
||||||
|
return AuthUser.builder()
|
||||||
|
.uuid(userObj.getString("id"))
|
||||||
|
.avatar(getAvatarUrl(userObj))
|
||||||
|
.nickname(userObj.getString("name"))
|
||||||
|
.company(getCompany(userObj))
|
||||||
|
.gender(getGender(userObj))
|
||||||
|
.token(authToken)
|
||||||
|
.source(source)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthResponse refresh(AuthToken authToken) {
|
||||||
|
return AuthResponse.builder()
|
||||||
|
.code(SUCCESS.getCode())
|
||||||
|
.data(getToken(this.refreshTokenUrl(authToken.getRefreshToken())))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuthToken getToken(String url) {
|
||||||
|
HttpResponse response = HttpRequest.post(url).execute();
|
||||||
|
JSONObject jsonObject = JSONObject.parseObject(response.body());
|
||||||
|
if (jsonObject.containsKey("error")) {
|
||||||
|
throw new AuthException("Failed to get token from Renren: " + jsonObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
return AuthToken.builder()
|
||||||
|
.tokenType(jsonObject.getString("token_type"))
|
||||||
|
.expireIn(jsonObject.getIntValue("expires_in"))
|
||||||
|
.accessToken(jsonObject.getString("access_token"))
|
||||||
|
.refreshToken(jsonObject.getString("refresh_token"))
|
||||||
|
.openId(jsonObject.getJSONObject("user").getString("id"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getAvatarUrl(JSONObject userObj) {
|
||||||
|
JSONArray jsonArray = userObj.getJSONArray("avatar");
|
||||||
|
if (Objects.isNull(jsonArray) || jsonArray.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return jsonArray.getJSONObject(0).getString("url");
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuthUserGender getGender(JSONObject userObj) {
|
||||||
|
JSONObject basicInformation = userObj.getJSONObject("basicInformation");
|
||||||
|
if (Objects.isNull(basicInformation)) {
|
||||||
|
return AuthUserGender.UNKNOWN;
|
||||||
|
}
|
||||||
|
return AuthUserGender.getRealGender(basicInformation.getString("sex"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getCompany(JSONObject userObj) {
|
||||||
|
JSONArray jsonArray = userObj.getJSONArray("work");
|
||||||
|
if (Objects.isNull(jsonArray) || jsonArray.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return jsonArray.getJSONObject(0).getString("name");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取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("userId", authToken.getOpenId())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
package me.zhyd.oauth.request;
|
package me.zhyd.oauth.request;
|
||||||
|
|
||||||
import me.zhyd.oauth.exception.AuthException;
|
import me.zhyd.oauth.exception.AuthException;
|
||||||
|
import me.zhyd.oauth.model.AuthCallback;
|
||||||
import me.zhyd.oauth.model.AuthResponse;
|
import me.zhyd.oauth.model.AuthResponse;
|
||||||
|
import me.zhyd.oauth.model.AuthResponseStatus;
|
||||||
import me.zhyd.oauth.model.AuthToken;
|
import me.zhyd.oauth.model.AuthToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,17 +19,17 @@ public interface AuthRequest {
|
|||||||
* @return 返回授权地址
|
* @return 返回授权地址
|
||||||
*/
|
*/
|
||||||
default String authorize() {
|
default String authorize() {
|
||||||
throw new AuthException(ResponseStatus.NOT_IMPLEMENTED);
|
throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 第三方登录
|
* 第三方登录
|
||||||
*
|
*
|
||||||
* @param code 通过authorize换回的code
|
* @param authCallback 用于接收回调参数的实体
|
||||||
* @return 返回登录成功后的用户信息
|
* @return 返回登录成功后的用户信息
|
||||||
*/
|
*/
|
||||||
default AuthResponse login(String code) {
|
default AuthResponse login(AuthCallback authCallback) {
|
||||||
throw new AuthException(ResponseStatus.NOT_IMPLEMENTED);
|
throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,7 +39,7 @@ public interface AuthRequest {
|
|||||||
* @return AuthResponse
|
* @return AuthResponse
|
||||||
*/
|
*/
|
||||||
default AuthResponse revoke(AuthToken authToken) {
|
default AuthResponse revoke(AuthToken authToken) {
|
||||||
throw new AuthException(ResponseStatus.NOT_IMPLEMENTED);
|
throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,6 +49,6 @@ public interface AuthRequest {
|
|||||||
* @return AuthResponse
|
* @return AuthResponse
|
||||||
*/
|
*/
|
||||||
default AuthResponse refresh(AuthToken authToken) {
|
default AuthResponse refresh(AuthToken authToken) {
|
||||||
throw new AuthException(ResponseStatus.NOT_IMPLEMENTED);
|
throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
package me.zhyd.oauth.request;
|
||||||
|
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import me.zhyd.oauth.config.AuthConfig;
|
||||||
|
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;
|
||||||
|
|
||||||
|
import static me.zhyd.oauth.config.AuthSource.STACK_OVERFLOW;
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
public class AuthStackOverflowRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
|
public AuthStackOverflowRequest(AuthConfig config) {
|
||||||
|
super(config, STACK_OVERFLOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
|
String accessTokenUrl = accessTokenUrl(authCallback.getCode());
|
||||||
|
HttpResponse response = HttpRequest.post(accessTokenUrl)
|
||||||
|
.contentType("application/x-www-form-urlencoded")
|
||||||
|
.form(parseQueryToMap(accessTokenUrl))
|
||||||
|
.execute();
|
||||||
|
JSONObject accessTokenObject = JSONObject.parseObject(response.body());
|
||||||
|
this.checkResponse(accessTokenObject);
|
||||||
|
|
||||||
|
return AuthToken.builder()
|
||||||
|
.accessToken(accessTokenObject.getString("access_token"))
|
||||||
|
.expireIn(accessTokenObject.getIntValue("expires"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
|
String userInfoUrl = UrlBuilder.fromBaseUrl(this.source.userInfo())
|
||||||
|
.queryParam("access_token", authToken.getAccessToken())
|
||||||
|
.queryParam("site", "stackoverflow")
|
||||||
|
.queryParam("key", this.config.getStackOverflowKey())
|
||||||
|
.build();
|
||||||
|
HttpResponse response = HttpRequest.get(userInfoUrl).execute();
|
||||||
|
JSONObject object = JSONObject.parseObject(response.body());
|
||||||
|
this.checkResponse(object);
|
||||||
|
JSONObject userObj = object.getJSONArray("items").getJSONObject(0);
|
||||||
|
|
||||||
|
return AuthUser.builder()
|
||||||
|
.uuid(userObj.getString("user_id"))
|
||||||
|
.avatar(userObj.getString("profile_image"))
|
||||||
|
.location(userObj.getString("location"))
|
||||||
|
.nickname(userObj.getString("display_name"))
|
||||||
|
.blog(userObj.getString("website_url"))
|
||||||
|
.gender(AuthUserGender.UNKNOWN)
|
||||||
|
.token(authToken)
|
||||||
|
.source(source)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
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")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查响应内容是否正确
|
||||||
|
*
|
||||||
|
* @param object 请求响应内容
|
||||||
|
*/
|
||||||
|
private void checkResponse(JSONObject object) {
|
||||||
|
if (object.containsKey("error")) {
|
||||||
|
throw new AuthException(object.getString("error_description"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
package me.zhyd.oauth.request;
|
package me.zhyd.oauth.request;
|
||||||
|
|
||||||
import cn.hutool.http.HttpRequest;
|
|
||||||
import cn.hutool.http.HttpResponse;
|
import cn.hutool.http.HttpResponse;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
import me.zhyd.oauth.config.AuthConfig;
|
||||||
|
import me.zhyd.oauth.config.AuthSource;
|
||||||
import me.zhyd.oauth.exception.AuthException;
|
import me.zhyd.oauth.exception.AuthException;
|
||||||
import me.zhyd.oauth.model.AuthSource;
|
import me.zhyd.oauth.model.AuthCallback;
|
||||||
import me.zhyd.oauth.model.AuthToken;
|
import me.zhyd.oauth.model.AuthToken;
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
import me.zhyd.oauth.model.AuthUserGender;
|
import me.zhyd.oauth.enums.AuthUserGender;
|
||||||
import me.zhyd.oauth.utils.GlobalAuthUtil;
|
import me.zhyd.oauth.utils.GlobalAuthUtil;
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
|
|
||||||
@@ -19,41 +19,54 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
public class AuthTaobaoRequest extends BaseAuthRequest {
|
public class AuthTaobaoRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
public AuthTaobaoRequest(AuthConfig config) {
|
public AuthTaobaoRequest(AuthConfig config) {
|
||||||
super(config, AuthSource.TAOBAO);
|
super(config, AuthSource.TAOBAO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthToken getAccessToken(String code) {
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
return AuthToken.builder()
|
return AuthToken.builder().accessCode(authCallback.getCode()).build();
|
||||||
.accessCode(code)
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
String accessCode = authToken.getAccessCode();
|
HttpResponse response = doPostAuthorizationCode(authToken.getAccessCode());
|
||||||
HttpResponse response = HttpRequest.post(UrlBuilder.getTaobaoAccessTokenUrl(this.config.getClientId(), this.config.getClientSecret(), accessCode, this.config.getRedirectUri())).execute();
|
JSONObject accessTokenObject = JSONObject.parseObject(response.body());
|
||||||
JSONObject object = JSONObject.parseObject(response.body());
|
if (accessTokenObject.containsKey("error")) {
|
||||||
if (object.containsKey("error")) {
|
throw new AuthException(accessTokenObject.getString("error_description"));
|
||||||
throw new AuthException(ResponseStatus.FAILURE + ":" + object.getString("error_description"));
|
|
||||||
}
|
}
|
||||||
authToken.setAccessToken(object.getString("access_token"));
|
authToken.setAccessToken(accessTokenObject.getString("access_token"));
|
||||||
authToken.setRefreshToken(object.getString("refresh_token"));
|
authToken.setRefreshToken(accessTokenObject.getString("refresh_token"));
|
||||||
authToken.setExpireIn(object.getIntValue("expires_in"));
|
authToken.setExpireIn(accessTokenObject.getIntValue("expires_in"));
|
||||||
authToken.setUid(object.getString("taobao_user_id"));
|
authToken.setUid(accessTokenObject.getString("taobao_user_id"));
|
||||||
authToken.setOpenId(object.getString("taobao_open_uid"));
|
authToken.setOpenId(accessTokenObject.getString("taobao_open_uid"));
|
||||||
|
|
||||||
String nick = GlobalAuthUtil.urlDecode(object.getString("taobao_user_nick"));
|
String nick = GlobalAuthUtil.urlDecode(accessTokenObject.getString("taobao_user_nick"));
|
||||||
return AuthUser.builder()
|
return AuthUser.builder()
|
||||||
.uuid(object.getString("taobao_user_id"))
|
.uuid(accessTokenObject.getString("taobao_user_id"))
|
||||||
.username(nick)
|
.username(nick)
|
||||||
.nickname(nick)
|
.nickname(nick)
|
||||||
.gender(AuthUserGender.UNKNOW)
|
.gender(AuthUserGender.UNKNOWN)
|
||||||
.token(authToken)
|
.token(authToken)
|
||||||
.source(AuthSource.TAOBAO)
|
.source(source)
|
||||||
.build();
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回认证url,可自行跳转页面
|
||||||
|
*
|
||||||
|
* @return 返回授权地址
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
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")
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
package me.zhyd.oauth.request;
|
||||||
|
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
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.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Teambition授权登录
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.8
|
||||||
|
*/
|
||||||
|
public class AuthTeambitionRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
|
public AuthTeambitionRequest(AuthConfig config) {
|
||||||
|
super(config, AuthSource.TEAMBITION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param authCallback 回调返回的参数
|
||||||
|
* @return 所有信息
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
|
HttpResponse response = HttpRequest.post(source.accessToken())
|
||||||
|
.form("client_id", config.getClientId())
|
||||||
|
.form("client_secret", config.getClientSecret())
|
||||||
|
.form("code", authCallback.getCode())
|
||||||
|
.form("grant_type", "code")
|
||||||
|
.execute();
|
||||||
|
JSONObject accessTokenObject = JSONObject.parseObject(response.body());
|
||||||
|
|
||||||
|
this.checkResponse(accessTokenObject);
|
||||||
|
|
||||||
|
return AuthToken.builder()
|
||||||
|
.accessToken(accessTokenObject.getString("access_token"))
|
||||||
|
.refreshToken(accessTokenObject.getString("refresh_token"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
|
String accessToken = authToken.getAccessToken();
|
||||||
|
|
||||||
|
HttpResponse response = HttpRequest.get(source.userInfo())
|
||||||
|
.header("Authorization", "OAuth2 " + accessToken)
|
||||||
|
.execute();
|
||||||
|
JSONObject object = JSONObject.parseObject(response.body());
|
||||||
|
|
||||||
|
this.checkResponse(object);
|
||||||
|
|
||||||
|
authToken.setUid(object.getString("_id"));
|
||||||
|
|
||||||
|
return AuthUser.builder()
|
||||||
|
.uuid(object.getString("_id"))
|
||||||
|
.username(object.getString("name"))
|
||||||
|
.nickname(object.getString("name"))
|
||||||
|
.avatar(object.getString("avatarUrl"))
|
||||||
|
.blog(object.getString("website"))
|
||||||
|
.location(object.getString("location"))
|
||||||
|
.email(object.getString("email"))
|
||||||
|
.gender(AuthUserGender.UNKNOWN)
|
||||||
|
.token(authToken)
|
||||||
|
.source(source)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthResponse refresh(AuthToken oldToken) {
|
||||||
|
String uid = oldToken.getUid();
|
||||||
|
String refreshToken = oldToken.getRefreshToken();
|
||||||
|
HttpResponse response = HttpRequest.post(source.refresh())
|
||||||
|
.form("_userId", uid)
|
||||||
|
.form("refresh_token", refreshToken)
|
||||||
|
.execute();
|
||||||
|
JSONObject refreshTokenObject = JSONObject.parseObject(response.body());
|
||||||
|
|
||||||
|
this.checkResponse(refreshTokenObject);
|
||||||
|
|
||||||
|
return AuthResponse.builder()
|
||||||
|
.code(AuthResponseStatus.SUCCESS.getCode())
|
||||||
|
.data(AuthToken.builder()
|
||||||
|
.accessToken(refreshTokenObject.getString("access_token"))
|
||||||
|
.refreshToken(refreshTokenObject.getString("refresh_token"))
|
||||||
|
.build())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查响应内容是否正确
|
||||||
|
*
|
||||||
|
* @param object 请求响应内容
|
||||||
|
*/
|
||||||
|
private void checkResponse(JSONObject object) {
|
||||||
|
if ((object.containsKey("message") && object.containsKey("name"))) {
|
||||||
|
throw new AuthException(object.getString("name") + ", " + object.getString("message"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
package me.zhyd.oauth.request;
|
package me.zhyd.oauth.request;
|
||||||
|
|
||||||
import cn.hutool.http.HttpRequest;
|
|
||||||
import cn.hutool.http.HttpResponse;
|
import cn.hutool.http.HttpResponse;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
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.exception.AuthException;
|
||||||
import me.zhyd.oauth.model.AuthSource;
|
import me.zhyd.oauth.model.AuthCallback;
|
||||||
import me.zhyd.oauth.model.AuthToken;
|
import me.zhyd.oauth.model.AuthToken;
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
import me.zhyd.oauth.model.AuthUserGender;
|
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,47 +18,71 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
public class AuthTencentCloudRequest extends BaseAuthRequest {
|
public class AuthTencentCloudRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
public AuthTencentCloudRequest(AuthConfig config) {
|
public AuthTencentCloudRequest(AuthConfig config) {
|
||||||
super(config, AuthSource.TENCEN_CLOUD);
|
super(config, AuthSource.TENCENT_CLOUD);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthToken getAccessToken(String code) {
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
String accessTokenUrl = UrlBuilder.getTencentCloudAccessTokenUrl(config.getClientId(), config.getClientSecret(), code);
|
HttpResponse response = doGetAuthorizationCode(authCallback.getCode());
|
||||||
HttpResponse response = HttpRequest.get(accessTokenUrl).execute();
|
JSONObject accessTokenObject = JSONObject.parseObject(response.body());
|
||||||
JSONObject object = JSONObject.parseObject(response.body());
|
this.checkResponse(accessTokenObject);
|
||||||
if (object.getIntValue("code") != 0) {
|
|
||||||
throw new AuthException("Unable to get token from tencent cloud using code [" + code + "]: " + object.get("msg"));
|
|
||||||
}
|
|
||||||
return AuthToken.builder()
|
return AuthToken.builder()
|
||||||
.accessToken(object.getString("access_token"))
|
.accessToken(accessTokenObject.getString("access_token"))
|
||||||
.build();
|
.expireIn(accessTokenObject.getIntValue("expires_in"))
|
||||||
|
.refreshToken(accessTokenObject.getString("refresh_token"))
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
String accessToken = authToken.getAccessToken();
|
HttpResponse response = doGetUserInfo(authToken);
|
||||||
HttpResponse response = HttpRequest.get(UrlBuilder.getTencentCloudUserInfoUrl(accessToken)).execute();
|
|
||||||
JSONObject object = JSONObject.parseObject(response.body());
|
JSONObject object = JSONObject.parseObject(response.body());
|
||||||
|
this.checkResponse(object);
|
||||||
|
|
||||||
|
object = object.getJSONObject("data");
|
||||||
|
return AuthUser.builder()
|
||||||
|
.uuid(object.getString("id"))
|
||||||
|
.username(object.getString("name"))
|
||||||
|
.avatar("https://dev.tencent.com/" + object.getString("avatar"))
|
||||||
|
.blog("https://dev.tencent.com/" + object.getString("path"))
|
||||||
|
.nickname(object.getString("name"))
|
||||||
|
.company(object.getString("company"))
|
||||||
|
.location(object.getString("location"))
|
||||||
|
.gender(AuthUserGender.getRealGender(object.getString("sex")))
|
||||||
|
.email(object.getString("email"))
|
||||||
|
.remark(object.getString("slogan"))
|
||||||
|
.token(authToken)
|
||||||
|
.source(source)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查响应内容是否正确
|
||||||
|
*
|
||||||
|
* @param object 请求响应内容
|
||||||
|
*/
|
||||||
|
private void checkResponse(JSONObject object) {
|
||||||
if (object.getIntValue("code") != 0) {
|
if (object.getIntValue("code") != 0) {
|
||||||
throw new AuthException(object.getString("msg"));
|
throw new AuthException(object.getString("msg"));
|
||||||
}
|
}
|
||||||
object = object.getJSONObject("data");
|
}
|
||||||
return AuthUser.builder()
|
|
||||||
.uuid(object.getString("id"))
|
/**
|
||||||
.username(object.getString("name"))
|
* 返回认证url,可自行跳转页面
|
||||||
.avatar("https://dev.tencent.com/" + object.getString("avatar"))
|
*
|
||||||
.blog("https://dev.tencent.com/" + object.getString("path"))
|
* @return 返回授权地址
|
||||||
.nickname(object.getString("name"))
|
*/
|
||||||
.company(object.getString("company"))
|
@Override
|
||||||
.location(object.getString("location"))
|
public String authorize() {
|
||||||
.gender(AuthUserGender.getRealGender(object.getString("sex")))
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
.email(object.getString("email"))
|
.queryParam("response_type", "code")
|
||||||
.remark(object.getString("slogan"))
|
.queryParam("client_id", config.getClientId())
|
||||||
.token(authToken)
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
.source(AuthSource.TENCEN_CLOUD)
|
.queryParam("scope", "user")
|
||||||
.build();
|
.queryParam("state", getRealState(config.getState()))
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,125 @@
|
|||||||
|
package me.zhyd.oauth.request;
|
||||||
|
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import me.zhyd.oauth.config.AuthConfig;
|
||||||
|
import me.zhyd.oauth.config.AuthSource;
|
||||||
|
import me.zhyd.oauth.enums.AuthToutiaoErrorCode;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 今日头条登录
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.5
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
public class AuthToutiaoRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
|
public AuthToutiaoRequest(AuthConfig config) {
|
||||||
|
super(config, AuthSource.TOUTIAO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
|
HttpResponse response = doGetAuthorizationCode(authCallback.getCode());
|
||||||
|
JSONObject accessTokenObject = JSONObject.parseObject(response.body());
|
||||||
|
|
||||||
|
this.checkResponse(accessTokenObject);
|
||||||
|
|
||||||
|
return AuthToken.builder()
|
||||||
|
.accessToken(accessTokenObject.getString("access_token"))
|
||||||
|
.expireIn(accessTokenObject.getIntValue("expires_in"))
|
||||||
|
.openId(accessTokenObject.getString("open_id"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
|
HttpResponse userResponse = doGetUserInfo(authToken);
|
||||||
|
|
||||||
|
JSONObject userProfile = JSONObject.parseObject(userResponse.body());
|
||||||
|
|
||||||
|
this.checkResponse(userProfile);
|
||||||
|
|
||||||
|
JSONObject user = userProfile.getJSONObject("data");
|
||||||
|
|
||||||
|
boolean isAnonymousUser = user.getIntValue("uid_type") == 14;
|
||||||
|
String anonymousUserName = "匿名用户";
|
||||||
|
|
||||||
|
return AuthUser.builder()
|
||||||
|
.uuid(user.getString("uid"))
|
||||||
|
.username(isAnonymousUser ? anonymousUserName : user.getString("screen_name"))
|
||||||
|
.nickname(isAnonymousUser ? anonymousUserName : user.getString("screen_name"))
|
||||||
|
.avatar(user.getString("avatar_url"))
|
||||||
|
.remark(user.getString("description"))
|
||||||
|
.gender(AuthUserGender.getRealGender(user.getString("gender")))
|
||||||
|
.token(authToken)
|
||||||
|
.source(source)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回认证url,可自行跳转页面
|
||||||
|
*
|
||||||
|
* @return 返回授权地址
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
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)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取accessToken的url
|
||||||
|
*
|
||||||
|
* @param code 授权码
|
||||||
|
* @return 返回获取accessToken的url
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String accessTokenUrl(String code) {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.accessToken())
|
||||||
|
.queryParam("code", code)
|
||||||
|
.queryParam("client_key", config.getClientId())
|
||||||
|
.queryParam("client_secret", config.getClientSecret())
|
||||||
|
.queryParam("grant_type", "authorization_code")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取userInfo的url
|
||||||
|
*
|
||||||
|
* @param authToken 用户授权后的token
|
||||||
|
* @return 返回获取userInfo的url
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String userInfoUrl(AuthToken authToken) {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.userInfo())
|
||||||
|
.queryParam("client_key", config.getClientId())
|
||||||
|
.queryParam("access_token", authToken.getAccessToken())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查响应内容是否正确
|
||||||
|
*
|
||||||
|
* @param object 请求响应内容
|
||||||
|
*/
|
||||||
|
private void checkResponse(JSONObject object) {
|
||||||
|
if (object.containsKey("error_code")) {
|
||||||
|
throw new AuthException(AuthToutiaoErrorCode.getErrorCode(object.getIntValue("error_code"))
|
||||||
|
.getDesc());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,8 @@ import cn.hutool.http.HttpRequest;
|
|||||||
import cn.hutool.http.HttpResponse;
|
import cn.hutool.http.HttpResponse;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
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.exception.AuthException;
|
||||||
import me.zhyd.oauth.model.*;
|
import me.zhyd.oauth.model.*;
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
@@ -15,7 +17,7 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
public class AuthWeChatRequest extends BaseAuthRequest {
|
public class AuthWeChatRequest extends AuthDefaultRequest {
|
||||||
public AuthWeChatRequest(AuthConfig config) {
|
public AuthWeChatRequest(AuthConfig config) {
|
||||||
super(config, AuthSource.WECHAT);
|
super(config, AuthSource.WECHAT);
|
||||||
}
|
}
|
||||||
@@ -23,58 +25,139 @@ public class AuthWeChatRequest extends BaseAuthRequest {
|
|||||||
/**
|
/**
|
||||||
* 微信的特殊性,此时返回的信息同时包含 openid 和 access_token
|
* 微信的特殊性,此时返回的信息同时包含 openid 和 access_token
|
||||||
*
|
*
|
||||||
* @param code 授权码
|
* @param authCallback 回调返回的参数
|
||||||
* @return 所有信息
|
* @return 所有信息
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected AuthToken getAccessToken(String code) {
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
String accessTokenUrl = UrlBuilder.getWeChatAccessTokenUrl(config.getClientId(), config.getClientSecret(), code);
|
return this.getToken(accessTokenUrl(authCallback.getCode()));
|
||||||
HttpResponse response = HttpRequest.get(accessTokenUrl).execute();
|
|
||||||
JSONObject object = JSONObject.parseObject(response.body());
|
|
||||||
if (!object.containsKey("access_token") || !object.containsKey("openid") || !object.containsKey("refresh_token")) {
|
|
||||||
throw new AuthException("Unable to get access_token or openid or refresh_token from wechat using code [" + code + "]");
|
|
||||||
}
|
|
||||||
return AuthToken.builder()
|
|
||||||
.accessToken(object.getString("access_token"))
|
|
||||||
.refreshToken(object.getString("refresh_token"))
|
|
||||||
.openId(object.getString("openid"))
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
String accessToken = authToken.getAccessToken();
|
|
||||||
String openId = authToken.getOpenId();
|
String openId = authToken.getOpenId();
|
||||||
|
|
||||||
HttpResponse response = HttpRequest.get(UrlBuilder.getWeChatUserInfoUrl(accessToken, openId)).execute();
|
HttpResponse response = doGetUserInfo(authToken);
|
||||||
JSONObject object = JSONObject.parseObject(response.body());
|
JSONObject object = JSONObject.parseObject(response.body());
|
||||||
if (object.containsKey("errcode")) {
|
|
||||||
throw new AuthException(object.getString("errmsg"));
|
this.checkResponse(object);
|
||||||
|
|
||||||
|
String location = String.format("%s-%s-%s", object.getString("country"), object.getString("province"), object.getString("city"));
|
||||||
|
|
||||||
|
if (object.containsKey("unionid")) {
|
||||||
|
authToken.setUnionId(object.getString("unionid"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return AuthUser.builder()
|
return AuthUser.builder()
|
||||||
.username(object.getString("nickname"))
|
.username(object.getString("nickname"))
|
||||||
.nickname(object.getString("nickname"))
|
.nickname(object.getString("nickname"))
|
||||||
.avatar(object.getString("headimgurl"))
|
.avatar(object.getString("headimgurl"))
|
||||||
.location(object.getString("country") + "-" + object.getString("province") + "-" + object.getString("city"))
|
.location(location)
|
||||||
.uuid(openId)
|
.uuid(openId)
|
||||||
.gender(AuthUserGender.getRealGender(object.getString("sex")))
|
.gender(AuthUserGender.getRealGender(object.getString("sex")))
|
||||||
.token(authToken)
|
.token(authToken)
|
||||||
.source(AuthSource.WECHAT)
|
.source(source)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AuthResponse refresh(AuthToken authToken) {
|
public AuthResponse refresh(AuthToken oldToken) {
|
||||||
String refreshToken = authToken.getRefreshToken();
|
return AuthResponse.builder()
|
||||||
HttpResponse response = HttpRequest.get(UrlBuilder.getWeChatRefreshUrl(config.getClientId(), refreshToken))
|
.code(AuthResponseStatus.SUCCESS.getCode())
|
||||||
.execute();
|
.data(this.getToken(refreshTokenUrl(oldToken.getRefreshToken())))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
JSONObject object = JSONObject.parseObject(response.body());
|
/**
|
||||||
|
* 检查响应内容是否正确
|
||||||
|
*
|
||||||
|
* @param object 请求响应内容
|
||||||
|
*/
|
||||||
|
private void checkResponse(JSONObject object) {
|
||||||
if (object.containsKey("errcode")) {
|
if (object.containsKey("errcode")) {
|
||||||
throw new AuthException(object.getString("errmsg"));
|
throw new AuthException(object.getIntValue("errcode"), object.getString("errmsg"));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return AuthResponse.builder().data(object).build();
|
/**
|
||||||
|
* 获取token,适用于获取access_token和刷新token
|
||||||
|
*
|
||||||
|
* @param accessTokenUrl 实际请求token的地址
|
||||||
|
* @return token对象
|
||||||
|
*/
|
||||||
|
private AuthToken getToken(String accessTokenUrl) {
|
||||||
|
HttpResponse response = HttpRequest.get(accessTokenUrl).execute();
|
||||||
|
JSONObject accessTokenObject = JSONObject.parseObject(response.body());
|
||||||
|
|
||||||
|
this.checkResponse(accessTokenObject);
|
||||||
|
|
||||||
|
return AuthToken.builder()
|
||||||
|
.accessToken(accessTokenObject.getString("access_token"))
|
||||||
|
.refreshToken(accessTokenObject.getString("refresh_token"))
|
||||||
|
.expireIn(accessTokenObject.getIntValue("expires_in"))
|
||||||
|
.openId(accessTokenObject.getString("openid"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回认证url,可自行跳转页面
|
||||||
|
*
|
||||||
|
* @return 返回授权地址
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
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"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取accessToken的url
|
||||||
|
*
|
||||||
|
* @param code 授权码
|
||||||
|
* @return 返回获取accessToken的url
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String accessTokenUrl(String code) {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.accessToken())
|
||||||
|
.queryParam("code", code)
|
||||||
|
.queryParam("appid", config.getClientId())
|
||||||
|
.queryParam("secret", config.getClientSecret())
|
||||||
|
.queryParam("grant_type", "authorization_code")
|
||||||
|
.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("openid", authToken.getOpenId())
|
||||||
|
.queryParam("lang", "zh_CN")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取userInfo的url
|
||||||
|
*
|
||||||
|
* @param refreshToken getAccessToken方法返回的refreshToken
|
||||||
|
* @return 返回获取userInfo的url
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String refreshTokenUrl(String refreshToken) {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.refresh())
|
||||||
|
.queryParam("appid", config.getClientId())
|
||||||
|
.queryParam("refresh_token", refreshToken)
|
||||||
|
.queryParam("grant_type", "refresh_token")
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,12 @@ import cn.hutool.http.HttpRequest;
|
|||||||
import cn.hutool.http.HttpResponse;
|
import cn.hutool.http.HttpResponse;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
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.exception.AuthException;
|
||||||
import me.zhyd.oauth.model.AuthSource;
|
import me.zhyd.oauth.model.AuthCallback;
|
||||||
import me.zhyd.oauth.model.AuthToken;
|
import me.zhyd.oauth.model.AuthToken;
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
import me.zhyd.oauth.model.AuthUserGender;
|
|
||||||
import me.zhyd.oauth.utils.IpUtils;
|
import me.zhyd.oauth.utils.IpUtils;
|
||||||
import me.zhyd.oauth.utils.StringUtils;
|
import me.zhyd.oauth.utils.StringUtils;
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
@@ -21,26 +22,26 @@ import me.zhyd.oauth.utils.UrlBuilder;
|
|||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
public class AuthWeiboRequest extends BaseAuthRequest {
|
public class AuthWeiboRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
public AuthWeiboRequest(AuthConfig config) {
|
public AuthWeiboRequest(AuthConfig config) {
|
||||||
super(config, AuthSource.WEIBO);
|
super(config, AuthSource.WEIBO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AuthToken getAccessToken(String code) {
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
String accessTokenUrl = UrlBuilder.getWeiboAccessTokenUrl(config.getClientId(), config.getClientSecret(), code, config.getRedirectUri());
|
HttpResponse response = doPostAuthorizationCode(authCallback.getCode());
|
||||||
HttpResponse response = HttpRequest.post(accessTokenUrl).execute();
|
|
||||||
String accessTokenStr = response.body();
|
String accessTokenStr = response.body();
|
||||||
JSONObject accessTokenObject = JSONObject.parseObject(accessTokenStr);
|
JSONObject accessTokenObject = JSONObject.parseObject(accessTokenStr);
|
||||||
if (accessTokenObject.containsKey("error")) {
|
if (accessTokenObject.containsKey("error")) {
|
||||||
throw new AuthException("Unable to get token from weibo using code [" + code + "]:" + accessTokenObject.getString("error_description"));
|
throw new AuthException(accessTokenObject.getString("error_description"));
|
||||||
}
|
}
|
||||||
return AuthToken.builder()
|
return AuthToken.builder()
|
||||||
.accessToken(accessTokenObject.getString("access_token"))
|
.accessToken(accessTokenObject.getString("access_token"))
|
||||||
.uid(accessTokenObject.getString("uid"))
|
.uid(accessTokenObject.getString("uid"))
|
||||||
.expireIn(accessTokenObject.getIntValue("remind_in"))
|
.openId(accessTokenObject.getString("uid"))
|
||||||
.build();
|
.expireIn(accessTokenObject.getIntValue("expires_in"))
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -48,26 +49,41 @@ public class AuthWeiboRequest extends BaseAuthRequest {
|
|||||||
String accessToken = authToken.getAccessToken();
|
String accessToken = authToken.getAccessToken();
|
||||||
String uid = authToken.getUid();
|
String uid = authToken.getUid();
|
||||||
String oauthParam = String.format("uid=%s&access_token=%s", uid, accessToken);
|
String oauthParam = String.format("uid=%s&access_token=%s", uid, accessToken);
|
||||||
HttpResponse response = HttpRequest.get(UrlBuilder.getWeiboUserInfoUrl(oauthParam))
|
HttpResponse response = HttpRequest.get(userInfoUrl(authToken))
|
||||||
.header("Authorization", "OAuth2 " + oauthParam)
|
.header("Authorization", "OAuth2 " + oauthParam)
|
||||||
.header("API-RemoteIP", IpUtils.getIp())
|
.header("API-RemoteIP", IpUtils.getIp())
|
||||||
.execute();
|
.execute();
|
||||||
String userInfo = response.body();
|
String userInfo = response.body();
|
||||||
JSONObject object = JSONObject.parseObject(userInfo);
|
JSONObject object = JSONObject.parseObject(userInfo);
|
||||||
if (object.containsKey("error")) {
|
if (object.containsKey("error")) {
|
||||||
throw new AuthException(object.getString("error"));
|
throw new AuthException(object.getString("error"));
|
||||||
}
|
}
|
||||||
return AuthUser.builder()
|
return AuthUser.builder()
|
||||||
.uuid(object.getString("id"))
|
.uuid(object.getString("id"))
|
||||||
.username(object.getString("name"))
|
.username(object.getString("name"))
|
||||||
.avatar(object.getString("profile_image_url"))
|
.avatar(object.getString("profile_image_url"))
|
||||||
.blog(StringUtils.isEmpty(object.getString("url")) ? "https://weibo.com/" + object.getString("profile_url") : object.getString("url"))
|
.blog(StringUtils.isEmpty(object.getString("url")) ? "https://weibo.com/" + object.getString("profile_url") : object
|
||||||
.nickname(object.getString("screen_name"))
|
.getString("url"))
|
||||||
.location(object.getString("location"))
|
.nickname(object.getString("screen_name"))
|
||||||
.remark(object.getString("description"))
|
.location(object.getString("location"))
|
||||||
.gender(AuthUserGender.getRealGender(object.getString("gender")))
|
.remark(object.getString("description"))
|
||||||
.token(authToken)
|
.gender(AuthUserGender.getRealGender(object.getString("gender")))
|
||||||
.source(AuthSource.WEIBO)
|
.token(authToken)
|
||||||
.build();
|
.source(source)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取userInfo的url
|
||||||
|
*
|
||||||
|
* @param authToken authToken
|
||||||
|
* @return 返回获取userInfo的url
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String userInfoUrl(AuthToken authToken) {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.userInfo())
|
||||||
|
.queryParam("access_token", authToken.getAccessToken())
|
||||||
|
.queryParam("uid", authToken.getUid())
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
package me.zhyd.oauth.request;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import me.zhyd.oauth.authorization.AuthorizationFactory;
|
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
|
||||||
import me.zhyd.oauth.exception.AuthException;
|
|
||||||
import me.zhyd.oauth.model.AuthResponse;
|
|
||||||
import me.zhyd.oauth.model.AuthSource;
|
|
||||||
import me.zhyd.oauth.model.AuthToken;
|
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
|
||||||
import me.zhyd.oauth.utils.AuthConfigChecker;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public abstract class BaseAuthRequest implements AuthRequest {
|
|
||||||
protected AuthConfig config;
|
|
||||||
protected AuthSource source;
|
|
||||||
|
|
||||||
public BaseAuthRequest(AuthConfig config, AuthSource source) {
|
|
||||||
this.config = config;
|
|
||||||
this.source = source;
|
|
||||||
if (!AuthConfigChecker.isSupportedAuth(config)) {
|
|
||||||
throw new AuthException(ResponseStatus.PARAMETER_INCOMPLETE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract AuthToken getAccessToken(String code);
|
|
||||||
|
|
||||||
protected abstract AuthUser getUserInfo(AuthToken authToken);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AuthResponse login(String code) {
|
|
||||||
try {
|
|
||||||
AuthUser user = this.getUserInfo(this.getAccessToken(code));
|
|
||||||
return AuthResponse.builder().code(ResponseStatus.SUCCESS.getCode()).data(user).build();
|
|
||||||
} catch (Exception e) {
|
|
||||||
return AuthResponse.builder().code(ResponseStatus.FAILURE.getCode()).msg(e.getMessage()).build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String authorize() {
|
|
||||||
return AuthorizationFactory.getAuthorize(source).getAuthorizeUrl(config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package me.zhyd.oauth.utils;
|
||||||
|
|
||||||
|
import me.zhyd.oauth.config.AuthConfig;
|
||||||
|
import me.zhyd.oauth.config.AuthSource;
|
||||||
|
import me.zhyd.oauth.exception.AuthException;
|
||||||
|
import me.zhyd.oauth.model.AuthResponseStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 授权配置类的校验器
|
||||||
|
*
|
||||||
|
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||||
|
* @version 1.0
|
||||||
|
* @since 1.8
|
||||||
|
*/
|
||||||
|
public class AuthChecker {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否支持第三方登录
|
||||||
|
*
|
||||||
|
* @param config config
|
||||||
|
* @param source source
|
||||||
|
* @return true or false
|
||||||
|
*/
|
||||||
|
public static boolean isSupportedAuth(AuthConfig config, AuthSource source) {
|
||||||
|
boolean isSupported = StringUtils.isNotEmpty(config.getClientId()) && StringUtils.isNotEmpty(config.getClientSecret()) && StringUtils.isNotEmpty(config.getRedirectUri());
|
||||||
|
if (isSupported && AuthSource.ALIPAY == source) {
|
||||||
|
isSupported = StringUtils.isNotEmpty(config.getAlipayPublicKey());
|
||||||
|
}
|
||||||
|
if (isSupported && AuthSource.STACK_OVERFLOW == source) {
|
||||||
|
isSupported = StringUtils.isNotEmpty(config.getStackOverflowKey());
|
||||||
|
}
|
||||||
|
return isSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查配置合法性。针对部分平台, 对redirect uri有特定要求。一般来说redirect uri都是http://,而对于facebook平台, redirect uri 必须是https的链接
|
||||||
|
*
|
||||||
|
* @param config config
|
||||||
|
* @param source source
|
||||||
|
*/
|
||||||
|
public static void checkConfig(AuthConfig config, AuthSource source) {
|
||||||
|
String redirectUri = config.getRedirectUri();
|
||||||
|
if (!GlobalAuthUtil.isHttpProtocol(redirectUri) && !GlobalAuthUtil.isHttpsProtocol(redirectUri)) {
|
||||||
|
throw new AuthException(AuthResponseStatus.ILLEGAL_REDIRECT_URI);
|
||||||
|
}
|
||||||
|
// facebook的回调地址必须为https的链接
|
||||||
|
if (AuthSource.FACEBOOK == source && !GlobalAuthUtil.isHttpsProtocol(redirectUri)) {
|
||||||
|
throw new AuthException(AuthResponseStatus.ILLEGAL_REDIRECT_URI);
|
||||||
|
}
|
||||||
|
// 支付宝在创建回调地址时,不允许使用localhost或者127.0.0.1
|
||||||
|
if (AuthSource.ALIPAY == source && GlobalAuthUtil.isLocalHost(redirectUri)) {
|
||||||
|
throw new AuthException(AuthResponseStatus.ILLEGAL_REDIRECT_URI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验回调传回的code
|
||||||
|
*
|
||||||
|
* @param code 回调时传回的code
|
||||||
|
*/
|
||||||
|
public static void checkCode(String 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,23 +0,0 @@
|
|||||||
package me.zhyd.oauth.utils;
|
|
||||||
|
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 授权配置类的校验器
|
|
||||||
*
|
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
|
||||||
* @version 1.0
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public class AuthConfigChecker {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否支持第三方登录
|
|
||||||
*
|
|
||||||
* @param config config
|
|
||||||
* @return true or false
|
|
||||||
*/
|
|
||||||
public static boolean isSupportedAuth(AuthConfig config) {
|
|
||||||
return StringUtils.isNotEmpty(config.getClientId()) && StringUtils.isNotEmpty(config.getClientSecret()) && StringUtils.isNotEmpty(config.getRedirectUri());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,185 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
package me.zhyd.oauth.utils;
|
package me.zhyd.oauth.utils;
|
||||||
|
|
||||||
import cn.hutool.core.codec.Base64;
|
import cn.hutool.core.codec.Base64;
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.http.HttpUtil;
|
||||||
import me.zhyd.oauth.exception.AuthException;
|
import me.zhyd.oauth.exception.AuthException;
|
||||||
|
|
||||||
import javax.crypto.Mac;
|
import javax.crypto.Mac;
|
||||||
@@ -8,11 +11,11 @@ import javax.crypto.spec.SecretKeySpec;
|
|||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 全局的工具类
|
* 全局的工具类
|
||||||
@@ -22,16 +25,12 @@ import java.util.Map;
|
|||||||
* @since 1.8
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
public class GlobalAuthUtil {
|
public class GlobalAuthUtil {
|
||||||
private static final String DEFAULT_ENCODING = "UTF-8";
|
private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
|
||||||
private static final String ALGORITHM = "HmacSHA256";
|
private static final String ALGORITHM = "HmacSHA256";
|
||||||
|
|
||||||
public static String generateDingTalkSignature(String canonicalString, String secret) {
|
public static String generateDingTalkSignature(String secretKey, String timestamp) {
|
||||||
try {
|
byte[] signData = sign(secretKey.getBytes(DEFAULT_ENCODING), timestamp.getBytes(DEFAULT_ENCODING));
|
||||||
byte[] signData = sign(canonicalString.getBytes(DEFAULT_ENCODING), secret.getBytes(DEFAULT_ENCODING));
|
return urlEncode(new String(Base64.encode(signData, false)));
|
||||||
return urlEncode(new String(Base64.encode(signData, false)));
|
|
||||||
} catch (UnsupportedEncodingException ex) {
|
|
||||||
throw new AuthException("Unsupported algorithm: " + DEFAULT_ENCODING, ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] sign(byte[] key, byte[] data) {
|
private static byte[] sign(byte[] key, byte[] data) {
|
||||||
@@ -46,15 +45,14 @@ public class GlobalAuthUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String urlEncode(String value) {
|
public static String urlEncode(String value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String encoded = URLEncoder.encode(value, GlobalAuthUtil.DEFAULT_ENCODING);
|
String encoded = URLEncoder.encode(value, GlobalAuthUtil.DEFAULT_ENCODING.displayName());
|
||||||
return encoded.replace("+", "%20").replace("*", "%2A")
|
return encoded.replace("+", "%20").replace("*", "%2A").replace("~", "%7E").replace("/", "%2F");
|
||||||
.replace("~", "%7E").replace("/", "%2F");
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
throw new AuthException("Failed To Encode Uri", e);
|
throw new AuthException("Failed To Encode Uri", e);
|
||||||
}
|
}
|
||||||
@@ -65,7 +63,7 @@ public class GlobalAuthUtil {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return URLDecoder.decode(value, GlobalAuthUtil.DEFAULT_ENCODING);
|
return URLDecoder.decode(value, GlobalAuthUtil.DEFAULT_ENCODING.displayName());
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
throw new AuthException("Failed To Decode Uri", e);
|
throw new AuthException("Failed To Decode Uri", e);
|
||||||
}
|
}
|
||||||
@@ -84,4 +82,43 @@ public class GlobalAuthUtil {
|
|||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String parseMapToString(Map<String, Object> params, boolean encode) {
|
||||||
|
List<String> paramList = new ArrayList<>();
|
||||||
|
params.forEach((k, v) -> {
|
||||||
|
if (ObjectUtil.isNull(v)) {
|
||||||
|
paramList.add(k + "=");
|
||||||
|
} else {
|
||||||
|
String valueString = v.toString();
|
||||||
|
paramList.add(k + "=" + (encode ? urlEncode(valueString) : valueString));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return CollUtil.join(paramList, "&");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, Object> parseQueryToMap(String url) {
|
||||||
|
Map<String, Object> paramMap = new HashMap<>();
|
||||||
|
HttpUtil.decodeParamMap(url, "UTF-8").forEach(paramMap::put);
|
||||||
|
return paramMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isHttpProtocol(String url) {
|
||||||
|
if (StringUtils.isEmpty(url)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return url.startsWith("http://");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isHttpsProtocol(String url) {
|
||||||
|
if (StringUtils.isEmpty(url)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return url.startsWith("https://");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isLocalHost(String url) {
|
||||||
|
return StringUtils.isEmpty(url) || url.contains("127.0.0.1") || url.contains("localhost");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,572 +1,79 @@
|
|||||||
package me.zhyd.oauth.utils;
|
package me.zhyd.oauth.utils;
|
||||||
|
|
||||||
import me.zhyd.oauth.consts.ApiUrl;
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.hutool.core.map.MapUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Url构建工具类
|
* <p>
|
||||||
|
* 构造URL
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
* @author yangkai.shen (https://xkcoding.com)
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since 1.0
|
* @since 1.8
|
||||||
*/
|
*/
|
||||||
|
@Setter
|
||||||
public class UrlBuilder {
|
public class UrlBuilder {
|
||||||
|
|
||||||
private static final String GITHUB_ACCESS_TOKEN_PATTERN = "{0}?client_id={1}&client_secret={2}&code={3}&redirect_uri={4}";
|
private final Map<String, Object> params = new LinkedHashMap<>(7);
|
||||||
private static final String GITHUB_USER_INFO_PATTERN = "{0}?access_token={1}";
|
private String baseUrl;
|
||||||
private static final String GITHUB_AUTHORIZE_PATTERN = "{0}?client_id={1}&state=1&redirect_uri={2}";
|
|
||||||
|
|
||||||
private static final String GOOGLE_AUTHORIZE_PATTERN = "{0}?client_id={1}&response_type=code&scope=openid%20email%20profile&redirect_uri={2}&state={3}";
|
private UrlBuilder() {
|
||||||
private static final String GOOGLE_ACCESS_TOKEN_PATTERN = "{0}?client_id={1}&client_secret={2}&code={3}&redirect_uri={4}&grant_type=authorization_code";
|
|
||||||
private static final String GOOGLE_USER_INFO_PATTERN = "{0}?id_token={1}";
|
|
||||||
|
|
||||||
private static final String WEIBO_ACCESS_TOKEN_PATTERN = "{0}?client_id={1}&client_secret={2}&grant_type=authorization_code&code={3}&redirect_uri={4}";
|
|
||||||
private static final String WEIBO_USER_INFO_PATTERN = "{0}?{1}";
|
|
||||||
private static final String WEIBO_AUTHORIZE_PATTERN = "{0}?client_id={1}&response_type=code&redirect_uri={2}";
|
|
||||||
|
|
||||||
private static final String GITEE_ACCESS_TOKEN_PATTERN = "{0}?client_id={1}&client_secret={2}&grant_type=authorization_code&code={3}&redirect_uri={4}";
|
|
||||||
private static final String GITEE_USER_INFO_PATTERN = "{0}?access_token={1}";
|
|
||||||
private static final String GITEE_AUTHORIZE_PATTERN = "{0}?client_id={1}&response_type=code&redirect_uri={2}";
|
|
||||||
|
|
||||||
private static final String DING_TALK_QRCONNECT_PATTERN = "{0}?appid={1}&response_type=code&scope=snsapi_login&state=STATE&redirect_uri={2}";
|
|
||||||
private static final String DING_TALK_USER_INFO_PATTERN = "{0}?signature={1}×tamp={2}&accessKey={3}";
|
|
||||||
|
|
||||||
private static final String BAIDU_ACCESS_TOKEN_PATTERN = "{0}?client_id={1}&client_secret={2}&grant_type=authorization_code&code={3}&redirect_uri={4}";
|
|
||||||
private static final String BAIDU_USER_INFO_PATTERN = "{0}?access_token={1}";
|
|
||||||
private static final String BAIDU_AUTHORIZE_PATTERN = "{0}?client_id={1}&response_type=code&redirect_uri={2}&display=popup";
|
|
||||||
private static final String BAIDU_REVOKE_PATTERN = "{0}?access_token={1}";
|
|
||||||
|
|
||||||
private static final String CSDN_ACCESS_TOKEN_PATTERN = "{0}?client_id={1}&client_secret={2}&grant_type=authorization_code&code={3}&redirect_uri={4}";
|
|
||||||
private static final String CSDN_USER_INFO_PATTERN = "{0}?access_token={1}";
|
|
||||||
private static final String CSDN_AUTHORIZE_PATTERN = "{0}?client_id={1}&response_type=code&redirect_uri={2}";
|
|
||||||
|
|
||||||
private static final String CODING_ACCESS_TOKEN_PATTERN = "{0}?client_id={1}&client_secret={2}&grant_type=authorization_code&code={3}";
|
|
||||||
private static final String CODING_USER_INFO_PATTERN = "{0}?access_token={1}";
|
|
||||||
private static final String CODING_AUTHORIZE_PATTERN = "{0}?client_id={1}&response_type=code&redirect_uri={2}&scope=user";
|
|
||||||
|
|
||||||
private static final String TENCENT_ACCESS_TOKEN_PATTERN = "{0}?client_id={1}&client_secret={2}&grant_type=authorization_code&code={3}";
|
|
||||||
private static final String TENCENT_USER_INFO_PATTERN = "{0}?access_token={1}";
|
|
||||||
private static final String TENCENT_AUTHORIZE_PATTERN = "{0}?client_id={1}&response_type=code&redirect_uri={2}&scope=user";
|
|
||||||
|
|
||||||
private static final String OSCHINA_ACCESS_TOKEN_PATTERN = "{0}?client_id={1}&client_secret={2}&grant_type=authorization_code&code={3}&redirect_uri={4}&dataType=json";
|
|
||||||
private static final String OSCHINA_USER_INFO_PATTERN = "{0}?access_token={1}&dataType=json";
|
|
||||||
private static final String OSCHINA_AUTHORIZE_PATTERN = "{0}?client_id={1}&response_type=code&redirect_uri={2}";
|
|
||||||
|
|
||||||
private static final String ALIPAY_AUTHORIZE_PATTERN = "{0}?app_id={1}&scope=auth_user&redirect_uri={2}&state=init";
|
|
||||||
|
|
||||||
private static final String QQ_ACCESS_TOKEN_PATTERN = "{0}?client_id={1}&client_secret={2}&grant_type=authorization_code&code={3}&redirect_uri={4}";
|
|
||||||
private static final String QQ_USER_INFO_PATTERN = "{0}?oauth_consumer_key={1}&access_token={2}&openid={3}";
|
|
||||||
private static final String QQ_AUTHORIZE_PATTERN = "{0}?client_id={1}&response_type=code&redirect_uri={2}&state={3}";
|
|
||||||
private static final String QQ_OPENID_PATTERN = "{0}?access_token={1}";
|
|
||||||
|
|
||||||
private static final String WECHAT_AUTHORIZE_PATTERN = "{0}?appid={1}&redirect_uri={2}&response_type=code&scope=snsapi_login&state={3}#wechat_redirect";
|
|
||||||
private static final String WECHAT_ACCESS_TOKEN_PATTERN = "{0}?appid={1}&secret={2}&code={3}&grant_type=authorization_code";
|
|
||||||
private static final String WECHAT_REFRESH_TOKEN_PATTERN = "{0}?appid={1}&grant_type=refresh_token&refresh_token={2}";
|
|
||||||
private static final String WECHAT_USER_INFO_PATTERN = "{0}?access_token={1}&openid={2}&lang=zh_CN";
|
|
||||||
|
|
||||||
private static final String TAOBAO_AUTHORIZE_PATTERN = "{0}?response_type=code&client_id={1}&redirect_uri={2}&state=&view=web";
|
|
||||||
private static final String TAOBAO_ACCESS_TOKEN_PATTERN = "{0}?client_id={1}&client_secret={2}&code={3}&redirect_uri={4}&grant_type=authorization_code";
|
|
||||||
|
|
||||||
private static final String FACEBOOK_AUTHORIZE_PATTERN = "{0}?client_id={1}&redirect_uri={2}&state={3}&response_type=code&scope=";
|
|
||||||
private static final String FACEBOOK_ACCESS_TOKEN_PATTERN = "{0}?client_id={1}&client_secret={2}&code={3}&redirect_uri={4}&grant_type=authorization_code";
|
|
||||||
private static final String FACEBOOK_USER_INFO_PATTERN = "{0}?access_token={1}&fields=id,name,birthday,gender,hometown,email,devices,picture.width(400)";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取githubtoken的接口地址
|
|
||||||
*
|
|
||||||
* @param clientId github应用的Client ID
|
|
||||||
* @param clientSecret github应用的Client Secret
|
|
||||||
* @param code github授权前的code,用来换token
|
|
||||||
* @param redirectUri 待跳转的页面
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getGithubAccessTokenUrl(String clientId, String clientSecret, String code, String redirectUri) {
|
|
||||||
return MessageFormat.format(GITHUB_ACCESS_TOKEN_PATTERN, ApiUrl.GITHUB.accessToken(), clientId, clientSecret, code, redirectUri);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取github用户详情的接口地址
|
* @param baseUrl 基础路径
|
||||||
*
|
* @return the new {@code UrlBuilder}
|
||||||
* @param token github 应用的token
|
|
||||||
* @return full url
|
|
||||||
*/
|
*/
|
||||||
public static String getGithubUserInfoUrl(String token) {
|
public static UrlBuilder fromBaseUrl(String baseUrl) {
|
||||||
return MessageFormat.format(GITHUB_USER_INFO_PATTERN, ApiUrl.GITHUB.userInfo(), token);
|
UrlBuilder builder = new UrlBuilder();
|
||||||
|
builder.setBaseUrl(baseUrl);
|
||||||
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取github授权地址
|
* 添加参数
|
||||||
*
|
*
|
||||||
* @param clientId github 应用的Client ID
|
* @param key 参数名称
|
||||||
* @param redirectUrl github 应用授权成功后的回调地址
|
* @param value 参数值
|
||||||
* @return full url
|
* @return this UrlBuilder
|
||||||
*/
|
*/
|
||||||
public static String getGithubAuthorizeUrl(String clientId, String redirectUrl) {
|
public UrlBuilder queryParam(String key, Object value) {
|
||||||
return MessageFormat.format(GITHUB_AUTHORIZE_PATTERN, ApiUrl.GITHUB.authorize(), clientId, redirectUrl);
|
Assert.notBlank(key, "参数名不能为空");
|
||||||
|
|
||||||
|
String valueAsString = (value != null ? value.toString() : null);
|
||||||
|
this.params.put(key, valueAsString);
|
||||||
|
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取weibo token的接口地址
|
* 构造url
|
||||||
*
|
*
|
||||||
* @param clientId weibo应用的App Key
|
* @return url
|
||||||
* @param clientSecret weibo应用的App Secret
|
|
||||||
* @param code weibo授权前的code,用来换token
|
|
||||||
* @param redirectUri 待跳转的页面
|
|
||||||
* @return full url
|
|
||||||
*/
|
*/
|
||||||
public static String getWeiboAccessTokenUrl(String clientId, String clientSecret, String code, String redirectUri) {
|
public String build() {
|
||||||
return MessageFormat.format(WEIBO_ACCESS_TOKEN_PATTERN, ApiUrl.WEIBO.accessToken(), clientId, clientSecret, code, redirectUri);
|
return this.build(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取weibo用户详情的接口地址
|
* 构造url
|
||||||
*
|
*
|
||||||
* @param token weibo 应用的token
|
* @param encode 转码
|
||||||
* @return full url
|
* @return url
|
||||||
*/
|
*/
|
||||||
public static String getWeiboUserInfoUrl(String token) {
|
public String build(boolean encode) {
|
||||||
return MessageFormat.format(WEIBO_USER_INFO_PATTERN, ApiUrl.WEIBO.userInfo(), token);
|
if (MapUtil.isEmpty(this.params)) {
|
||||||
}
|
return this.baseUrl;
|
||||||
|
}
|
||||||
/**
|
String baseUrl = StrUtil.addSuffixIfNot(this.baseUrl, "?");
|
||||||
* 获取weibo授权地址
|
String paramString = GlobalAuthUtil.parseMapToString(this.params, encode);
|
||||||
*
|
return baseUrl + paramString;
|
||||||
* @param clientId weibo 应用的Client ID
|
|
||||||
* @param redirectUrl weibo 应用授权成功后的回调地址
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getWeiboAuthorizeUrl(String clientId, String redirectUrl) {
|
|
||||||
return MessageFormat.format(WEIBO_AUTHORIZE_PATTERN, ApiUrl.WEIBO.authorize(), clientId, redirectUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取gitee token的接口地址
|
|
||||||
*
|
|
||||||
* @param clientId gitee应用的Client ID
|
|
||||||
* @param clientSecret gitee应用的Client Secret
|
|
||||||
* @param code gitee授权前的code,用来换token
|
|
||||||
* @param redirectUri 待跳转的页面
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getGiteeAccessTokenUrl(String clientId, String clientSecret, String code, String redirectUri) {
|
|
||||||
return MessageFormat.format(GITEE_ACCESS_TOKEN_PATTERN, ApiUrl.GITEE.accessToken(), clientId, clientSecret, code, redirectUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取gitee用户详情的接口地址
|
|
||||||
*
|
|
||||||
* @param token gitee 应用的token
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getGiteeUserInfoUrl(String token) {
|
|
||||||
return MessageFormat.format(GITEE_USER_INFO_PATTERN, ApiUrl.GITEE.userInfo(), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取gitee授权地址
|
|
||||||
*
|
|
||||||
* @param clientId gitee 应用的Client ID
|
|
||||||
* @param redirectUrl gitee 应用授权成功后的回调地址
|
|
||||||
* @return json
|
|
||||||
*/
|
|
||||||
public static String getGiteeAuthorizeUrl(String clientId, String redirectUrl) {
|
|
||||||
return MessageFormat.format(GITEE_AUTHORIZE_PATTERN, ApiUrl.GITEE.authorize(), clientId, redirectUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取钉钉登录二维码的地址
|
|
||||||
*
|
|
||||||
* @param clientId 钉钉 应用的App Id
|
|
||||||
* @param redirectUrl 钉钉 应用授权成功后的回调地址
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getDingTalkQrConnectUrl(String clientId, String redirectUrl) {
|
|
||||||
return MessageFormat.format(DING_TALK_QRCONNECT_PATTERN, ApiUrl.DINGTALK.authorize(), clientId, redirectUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取钉钉用户信息的地址
|
|
||||||
*
|
|
||||||
* @param signature 通过appSecret计算出来的签名值,签名计算方法:https://open-doc.dingtalk.com/microapp/faquestions/hxs5v9
|
|
||||||
* @param timestamp 当前时间戳,单位是毫秒
|
|
||||||
* @param accessKey 钉钉 应用的App Id
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getDingTalkUserInfoUrl(String signature, String timestamp, String accessKey) {
|
|
||||||
return MessageFormat.format(DING_TALK_USER_INFO_PATTERN, ApiUrl.DINGTALK.userInfo(), signature, timestamp, accessKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取baidu token的接口地址
|
|
||||||
*
|
|
||||||
* @param clientId baidu应用的API Key
|
|
||||||
* @param clientSecret baidu应用的Secret Key
|
|
||||||
* @param code baidu授权前的code,用来换token
|
|
||||||
* @param redirectUri 待跳转的页面
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getBaiduAccessTokenUrl(String clientId, String clientSecret, String code, String redirectUri) {
|
|
||||||
return MessageFormat.format(BAIDU_ACCESS_TOKEN_PATTERN, ApiUrl.BAIDU.accessToken(), clientId, clientSecret, code, redirectUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取baidu用户详情的接口地址
|
|
||||||
*
|
|
||||||
* @param token baidu 应用的token
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getBaiduUserInfoUrl(String token) {
|
|
||||||
return MessageFormat.format(BAIDU_USER_INFO_PATTERN, ApiUrl.BAIDU.userInfo(), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取baidu授权地址
|
|
||||||
*
|
|
||||||
* @param clientId baidu 应用的API Key
|
|
||||||
* @param redirectUrl baidu 应用授权成功后的回调地址
|
|
||||||
* @return json
|
|
||||||
*/
|
|
||||||
public static String getBaiduAuthorizeUrl(String clientId, String redirectUrl) {
|
|
||||||
return MessageFormat.format(BAIDU_AUTHORIZE_PATTERN, ApiUrl.BAIDU.authorize(), clientId, redirectUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取收回baidu授权的地址
|
|
||||||
*
|
|
||||||
* @param accessToken baidu授权登录后的token
|
|
||||||
* @return json
|
|
||||||
*/
|
|
||||||
public static String getBaiduRevokeUrl(String accessToken) {
|
|
||||||
return MessageFormat.format(BAIDU_REVOKE_PATTERN, ApiUrl.BAIDU.revoke(), accessToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取csdn token的接口地址
|
|
||||||
*
|
|
||||||
* @param clientId csdn应用的App Key
|
|
||||||
* @param clientSecret csdn应用的App Secret
|
|
||||||
* @param code csdn授权前的code,用来换token
|
|
||||||
* @param redirectUri 待跳转的页面
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getCsdnAccessTokenUrl(String clientId, String clientSecret, String code, String redirectUri) {
|
|
||||||
return MessageFormat.format(CSDN_ACCESS_TOKEN_PATTERN, ApiUrl.CSDN.accessToken(), clientId, clientSecret, code, redirectUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取csdn用户详情的接口地址
|
|
||||||
*
|
|
||||||
* @param token csdn 应用的token
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getCsdnUserInfoUrl(String token) {
|
|
||||||
return MessageFormat.format(CSDN_USER_INFO_PATTERN, ApiUrl.CSDN.userInfo(), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取csdn授权地址
|
|
||||||
*
|
|
||||||
* @param clientId csdn 应用的Client ID
|
|
||||||
* @param redirectUrl csdn 应用授权成功后的回调地址
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getCsdnAuthorizeUrl(String clientId, String redirectUrl) {
|
|
||||||
return MessageFormat.format(CSDN_AUTHORIZE_PATTERN, ApiUrl.CSDN.authorize(), clientId, redirectUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取coding token的接口地址
|
|
||||||
*
|
|
||||||
* @param clientId coding应用的App Key
|
|
||||||
* @param clientSecret coding应用的App Secret
|
|
||||||
* @param code coding授权前的code,用来换token
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getCodingAccessTokenUrl(String clientId, String clientSecret, String code) {
|
|
||||||
return MessageFormat.format(CODING_ACCESS_TOKEN_PATTERN, ApiUrl.CODING.accessToken(), clientId, clientSecret, code);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取coding用户详情的接口地址
|
|
||||||
*
|
|
||||||
* @param token coding 应用的token
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getCodingUserInfoUrl(String token) {
|
|
||||||
return MessageFormat.format(CODING_USER_INFO_PATTERN, ApiUrl.CODING.userInfo(), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取coding授权地址
|
|
||||||
*
|
|
||||||
* @param clientId coding 应用的Client ID
|
|
||||||
* @param redirectUrl coding 应用授权成功后的回调地址
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getCodingAuthorizeUrl(String clientId, String redirectUrl) {
|
|
||||||
return MessageFormat.format(CODING_AUTHORIZE_PATTERN, ApiUrl.CODING.authorize(), clientId, redirectUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取腾讯云开发者平台 token的接口地址
|
|
||||||
*
|
|
||||||
* @param clientId coding应用的App Key
|
|
||||||
* @param clientSecret coding应用的App Secret
|
|
||||||
* @param code coding授权前的code,用来换token
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getTencentCloudAccessTokenUrl(String clientId, String clientSecret, String code) {
|
|
||||||
return MessageFormat.format(TENCENT_ACCESS_TOKEN_PATTERN, ApiUrl.TENCENTCLOUD.accessToken(), clientId, clientSecret, code);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取腾讯云开发者平台用户详情的接口地址
|
|
||||||
*
|
|
||||||
* @param token coding 应用的token
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getTencentCloudUserInfoUrl(String token) {
|
|
||||||
return MessageFormat.format(TENCENT_USER_INFO_PATTERN, ApiUrl.TENCENTCLOUD.userInfo(), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取腾讯云开发者平台授权地址
|
|
||||||
*
|
|
||||||
* @param clientId coding 应用的Client ID
|
|
||||||
* @param redirectUrl coding 应用授权成功后的回调地址
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getTencentCloudAuthorizeUrl(String clientId, String redirectUrl) {
|
|
||||||
return MessageFormat.format(TENCENT_AUTHORIZE_PATTERN, ApiUrl.TENCENTCLOUD.authorize(), clientId, redirectUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取oschina token的接口地址
|
|
||||||
*
|
|
||||||
* @param clientId oschina应用的App Key
|
|
||||||
* @param clientSecret oschina应用的App Secret
|
|
||||||
* @param code oschina授权前的code,用来换token
|
|
||||||
* @param redirectUri 待跳转的页面
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getOschinaAccessTokenUrl(String clientId, String clientSecret, String code, String redirectUri) {
|
|
||||||
return MessageFormat.format(OSCHINA_ACCESS_TOKEN_PATTERN, ApiUrl.OSCHINA.accessToken(), clientId, clientSecret, code, redirectUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取oschina用户详情的接口地址
|
|
||||||
*
|
|
||||||
* @param token oschina 应用的token
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getOschinaUserInfoUrl(String token) {
|
|
||||||
return MessageFormat.format(OSCHINA_USER_INFO_PATTERN, ApiUrl.OSCHINA.userInfo(), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取oschina授权地址
|
|
||||||
*
|
|
||||||
* @param clientId oschina 应用的Client ID
|
|
||||||
* @param redirectUrl oschina 应用授权成功后的回调地址
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getOschinaAuthorizeUrl(String clientId, String redirectUrl) {
|
|
||||||
return MessageFormat.format(OSCHINA_AUTHORIZE_PATTERN, ApiUrl.OSCHINA.authorize(), clientId, redirectUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取qq token的接口地址
|
|
||||||
*
|
|
||||||
* @param clientId qq应用的App Key
|
|
||||||
* @param clientSecret qq应用的App Secret
|
|
||||||
* @param code qq授权前的code,用来换token
|
|
||||||
* @param redirectUri 待跳转的页面
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getQqAccessTokenUrl(String clientId, String clientSecret, String code, String redirectUri) {
|
|
||||||
return MessageFormat.format(QQ_ACCESS_TOKEN_PATTERN, ApiUrl.QQ.accessToken(), clientId, clientSecret, code, redirectUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取qq用户详情的接口地址
|
|
||||||
*
|
|
||||||
* @param token qq 应用的token
|
|
||||||
* @param openId qq 应用的openId
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getQqUserInfoUrl(String clientId, String token, String openId) {
|
|
||||||
return MessageFormat.format(QQ_USER_INFO_PATTERN, ApiUrl.QQ.userInfo(), clientId, token, openId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取qq授权地址
|
|
||||||
*
|
|
||||||
* @param clientId qq 应用的Client ID
|
|
||||||
* @param redirectUrl qq 应用授权成功后的回调地址
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getQqAuthorizeUrl(String clientId, String redirectUrl) {
|
|
||||||
return MessageFormat.format(QQ_AUTHORIZE_PATTERN, ApiUrl.QQ.authorize(), clientId, redirectUrl, System.currentTimeMillis());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取qq授权地址
|
|
||||||
*
|
|
||||||
* @param url 获取qqopenid的api接口地址
|
|
||||||
* @param token qq 应用授权的token
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getQqOpenidUrl(String url, String token) {
|
|
||||||
return MessageFormat.format(QQ_OPENID_PATTERN, url, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取alipay授权地址
|
|
||||||
*
|
|
||||||
* @param clientId alipay 应用的Client ID
|
|
||||||
* @param redirectUrl alipay 应用授权成功后的回调地址
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getAlipayAuthorizeUrl(String clientId, String redirectUrl) {
|
|
||||||
return MessageFormat.format(ALIPAY_AUTHORIZE_PATTERN, ApiUrl.ALIPAY.authorize(), clientId, redirectUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取微信 授权地址
|
|
||||||
*
|
|
||||||
* @param clientId 微信应用的appid
|
|
||||||
* @param redirectUrl 微信应用授权成功后的回调地址
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getWeChatAuthorizeUrl(String clientId, String redirectUrl) {
|
|
||||||
return MessageFormat.format(WECHAT_AUTHORIZE_PATTERN, ApiUrl.WECHAT.authorize(), clientId, redirectUrl, System.currentTimeMillis());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取微信 token的接口地址
|
|
||||||
*
|
|
||||||
* @param clientId 微信应用的appid
|
|
||||||
* @param clientSecret 微信应用的secret
|
|
||||||
* @param code 微信授权前的code,用来换token
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getWeChatAccessTokenUrl(String clientId, String clientSecret, String code) {
|
|
||||||
return MessageFormat.format(WECHAT_ACCESS_TOKEN_PATTERN, ApiUrl.WECHAT.accessToken(), clientId, clientSecret, code);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取微信 用户详情的接口地址
|
|
||||||
*
|
|
||||||
* @param token 微信应用返回的 access token
|
|
||||||
* @param openId 微信应用返回的openId
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getWeChatUserInfoUrl(String token, String openId) {
|
|
||||||
return MessageFormat.format(WECHAT_USER_INFO_PATTERN, ApiUrl.WECHAT.userInfo(), token, openId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取微信 刷新令牌 地址
|
|
||||||
*
|
|
||||||
* @param clientId 微信应用的appid
|
|
||||||
* @param refreshToken 微信应用返回的刷新token
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getWeChatRefreshUrl(String clientId, String refreshToken) {
|
|
||||||
return MessageFormat.format(WECHAT_REFRESH_TOKEN_PATTERN, ApiUrl.WECHAT.refresh(), clientId, refreshToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取Taobao token的接口地址: 淘宝的授权登录,在这一步就会返回用户信息
|
|
||||||
*
|
|
||||||
* @param clientId taobao应用的App Key
|
|
||||||
* @param clientSecret taobao应用的App Secret
|
|
||||||
* @param code taobao授权前的code,用来换token
|
|
||||||
* @param redirectUri 待跳转的页面
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getTaobaoAccessTokenUrl(String clientId, String clientSecret, String code, String redirectUri) {
|
|
||||||
return MessageFormat.format(TAOBAO_ACCESS_TOKEN_PATTERN, ApiUrl.TAOBAO.accessToken(), clientId, clientSecret, code, redirectUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取Taobao授权地址
|
|
||||||
*
|
|
||||||
* @param clientId Taobao 应用的Client ID
|
|
||||||
* @param redirectUrl Taobao 应用授权成功后的回调地址
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getTaobaoAuthorizeUrl(String clientId, String redirectUrl) {
|
|
||||||
return MessageFormat.format(TAOBAO_AUTHORIZE_PATTERN, ApiUrl.TAOBAO.authorize(), clientId, redirectUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取Google授权地址
|
|
||||||
*
|
|
||||||
* @param clientId google 应用的Client ID
|
|
||||||
* @param redirectUrl google 应用授权成功后的回调地址
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getGoogleAuthorizeUrl(String clientId, String redirectUrl) {
|
|
||||||
return MessageFormat.format(GOOGLE_AUTHORIZE_PATTERN, ApiUrl.GOOGLE.authorize(), clientId, redirectUrl, System.currentTimeMillis());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取Google token的接口地址
|
|
||||||
*
|
|
||||||
* @param clientId google应用的Client ID
|
|
||||||
* @param clientSecret google应用的Client Secret
|
|
||||||
* @param code google授权前的code,用来换token
|
|
||||||
* @param redirectUri 待跳转的页面
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getGoogleAccessTokenUrl(String clientId, String clientSecret, String code, String redirectUri) {
|
|
||||||
return MessageFormat.format(GOOGLE_ACCESS_TOKEN_PATTERN, ApiUrl.GOOGLE.accessToken(), clientId, clientSecret, code, redirectUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取Google用户详情的接口地址
|
|
||||||
*
|
|
||||||
* @param token google 应用的token
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getGoogleUserInfoUrl(String token) {
|
|
||||||
return MessageFormat.format(GOOGLE_USER_INFO_PATTERN, ApiUrl.GOOGLE.userInfo(), token);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取Facebook授权地址
|
|
||||||
*
|
|
||||||
* @param clientId Facebook 应用的Client ID
|
|
||||||
* @param redirectUrl Facebook 应用授权成功后的回调地址
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getFacebookAuthorizeUrl(String clientId, String redirectUrl) {
|
|
||||||
return MessageFormat.format(FACEBOOK_AUTHORIZE_PATTERN, ApiUrl.FACEBOOK.authorize(), clientId, redirectUrl, System
|
|
||||||
.currentTimeMillis());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取Facebook token的接口地址
|
|
||||||
*
|
|
||||||
* @param clientId Facebook 应用的Client ID
|
|
||||||
* @param clientSecret Facebook 应用的Client Secret
|
|
||||||
* @param code Facebook 授权前的code,用来换token
|
|
||||||
* @param redirectUri 待跳转的页面
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getFacebookAccessTokenUrl(String clientId, String clientSecret, String code, String redirectUri) {
|
|
||||||
return MessageFormat.format(FACEBOOK_ACCESS_TOKEN_PATTERN, ApiUrl.FACEBOOK.accessToken(), clientId, clientSecret, code, redirectUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取Facebook用户详情的接口地址
|
|
||||||
*
|
|
||||||
* @param token Facebook 应用的token
|
|
||||||
* @return full url
|
|
||||||
*/
|
|
||||||
public static String getFacebookUserInfoUrl(String token) {
|
|
||||||
return MessageFormat.format(FACEBOOK_USER_INFO_PATTERN, ApiUrl.FACEBOOK.userInfo(), token);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package me.zhyd.oauth;
|
package me.zhyd.oauth;
|
||||||
|
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
import me.zhyd.oauth.config.AuthConfig;
|
||||||
|
import me.zhyd.oauth.model.AuthCallback;
|
||||||
import me.zhyd.oauth.model.AuthResponse;
|
import me.zhyd.oauth.model.AuthResponse;
|
||||||
import me.zhyd.oauth.request.*;
|
import me.zhyd.oauth.request.*;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -18,11 +19,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
|
.state("state")
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行调整
|
// 返回授权页面,可自行跳转
|
||||||
authRequest.authorize();
|
authRequest.authorize();
|
||||||
// 授权登录后会返回一个code,用这个code进行登录
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
authRequest.login("code");
|
authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -31,11 +33,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
|
.state("state")
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行调整
|
// 返回授权页面,可自行跳转
|
||||||
authRequest.authorize();
|
authRequest.authorize();
|
||||||
// 授权登录后会返回一个code,用这个code进行登录
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
authRequest.login("code");
|
authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -45,10 +48,10 @@ public class AuthRequestTest {
|
|||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行调整
|
// 返回授权页面,可自行跳转
|
||||||
authRequest.authorize();
|
authRequest.authorize();
|
||||||
// 授权登录后会返回一个code,用这个code进行登录
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
authRequest.login("code");
|
authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -57,11 +60,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
|
.state("state")
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行调整
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
String url = authRequest.authorize();
|
||||||
// 授权登录后会返回一个code,用这个code进行登录
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
authRequest.login("code");
|
authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -70,11 +74,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
|
.state("state")
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行调整
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
String url = authRequest.authorize();
|
||||||
// 授权登录后会返回一个code,用这个code进行登录
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
authRequest.login("code");
|
authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -83,11 +88,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
|
.state("state")
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行调整
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
String url = authRequest.authorize();
|
||||||
// 授权登录后会返回一个code,用这个code进行登录
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
authRequest.login("code");
|
authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -96,11 +102,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
|
.state("state")
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行调整
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
String url = authRequest.authorize();
|
||||||
// 授权登录后会返回一个code,用这个code进行登录
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
authRequest.login("code");
|
authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -109,11 +116,27 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
|
.state("state")
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行调整
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
String url = authRequest.authorize();
|
||||||
// 授权登录后会返回一个code,用这个code进行登录
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
authRequest.login("code");
|
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());
|
||||||
|
// 返回授权页面,可自行跳转
|
||||||
|
String url = authRequest.authorize();
|
||||||
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
AuthResponse login = authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -122,11 +145,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
|
.state("state")
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行调整
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
String url = authRequest.authorize();
|
||||||
// 授权登录后会返回一个code,用这个code进行登录
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
AuthResponse login = authRequest.login("code");
|
AuthResponse login = authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -135,11 +159,26 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
|
.state("state")
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行调整
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
String url = authRequest.authorize();
|
||||||
// 授权登录后会返回一个code,用这个code进行登录
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
AuthResponse login = authRequest.login("code");
|
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());
|
||||||
|
// 返回授权页面,可自行跳转
|
||||||
|
String url = authRequest.authorize();
|
||||||
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
AuthResponse login = authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -148,11 +187,12 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
|
.state("state")
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行调整
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
String url = authRequest.authorize();
|
||||||
// 授权登录后会返回一个code,用这个code进行登录
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
AuthResponse login = authRequest.login("code");
|
AuthResponse login = authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -161,10 +201,81 @@ public class AuthRequestTest {
|
|||||||
.clientId("clientId")
|
.clientId("clientId")
|
||||||
.clientSecret("clientSecret")
|
.clientSecret("clientSecret")
|
||||||
.redirectUri("redirectUri")
|
.redirectUri("redirectUri")
|
||||||
|
.state("state")
|
||||||
.build());
|
.build());
|
||||||
// 返回授权页面,可自行调整
|
// 返回授权页面,可自行跳转
|
||||||
String url = authRequest.authorize();
|
String url = authRequest.authorize();
|
||||||
// 授权登录后会返回一个code,用这个code进行登录
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
AuthResponse login = authRequest.login("code");
|
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());
|
||||||
|
// 返回授权页面,可自行跳转
|
||||||
|
String url = authRequest.authorize();
|
||||||
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
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());
|
||||||
|
// 返回授权页面,可自行跳转
|
||||||
|
String url = authRequest.authorize();
|
||||||
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
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());
|
||||||
|
// 返回授权页面,可自行跳转
|
||||||
|
String url = authRequest.authorize();
|
||||||
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
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());
|
||||||
|
// 返回授权页面,可自行跳转
|
||||||
|
String url = authRequest.authorize();
|
||||||
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
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());
|
||||||
|
// 返回授权页面,可自行跳转
|
||||||
|
String url = authRequest.authorize();
|
||||||
|
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的入参
|
||||||
|
AuthResponse login = authRequest.login(new AuthCallback());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,231 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
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,61 @@
|
|||||||
|
package me.zhyd.oauth.utils;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class GlobalAuthUtilTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGenerateDingTalkSignature() {
|
||||||
|
Assert.assertEquals("mLTZEMqIlpAA3xtJ43KcRT0EDLwgSamFe%2FNis5lq9ik%3D",
|
||||||
|
GlobalAuthUtil.generateDingTalkSignature(
|
||||||
|
"SHA-256", "1562325753000 "));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUrlDecode() {
|
||||||
|
Assert.assertEquals("", GlobalAuthUtil.urlDecode(null));
|
||||||
|
Assert.assertEquals("https://www.foo.bar",
|
||||||
|
GlobalAuthUtil.urlDecode("https://www.foo.bar"));
|
||||||
|
Assert.assertEquals("mLTZEMqIlpAA3xtJ43KcRT0EDLwgSamFe/Nis5lq9ik=",
|
||||||
|
GlobalAuthUtil.urlDecode(
|
||||||
|
"mLTZEMqIlpAA3xtJ43KcRT0EDLwgSamFe%2FNis5lq9ik%3D"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseStringToMap() {
|
||||||
|
Map expected = new HashMap();
|
||||||
|
expected.put("bar", "baz");
|
||||||
|
Assert.assertEquals(expected,
|
||||||
|
GlobalAuthUtil.parseStringToMap("foo&bar=baz"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsHttpProtocol() {
|
||||||
|
Assert.assertFalse(GlobalAuthUtil.isHttpProtocol(""));
|
||||||
|
Assert.assertFalse(GlobalAuthUtil.isHttpProtocol("foo"));
|
||||||
|
|
||||||
|
Assert.assertTrue(GlobalAuthUtil.isHttpProtocol("http://www.foo.bar"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsHttpsProtocol() {
|
||||||
|
Assert.assertFalse(GlobalAuthUtil.isHttpsProtocol(""));
|
||||||
|
Assert.assertFalse(GlobalAuthUtil.isHttpsProtocol("foo"));
|
||||||
|
|
||||||
|
Assert.assertTrue(
|
||||||
|
GlobalAuthUtil.isHttpsProtocol("https://www.foo.bar"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsLocalHost() {
|
||||||
|
Assert.assertFalse(GlobalAuthUtil.isLocalHost("foo"));
|
||||||
|
|
||||||
|
Assert.assertTrue(GlobalAuthUtil.isLocalHost(""));
|
||||||
|
Assert.assertTrue(GlobalAuthUtil.isLocalHost("127.0.0.1"));
|
||||||
|
Assert.assertTrue(GlobalAuthUtil.isLocalHost("localhost"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package me.zhyd.oauth.utils;
|
||||||
|
|
||||||
|
import me.zhyd.oauth.config.AuthConfig;
|
||||||
|
import me.zhyd.oauth.config.AuthSource;
|
||||||
|
import me.zhyd.oauth.request.AuthWeChatRequest;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* UrlBuilder测试类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author yangkai.shen (https://xkcoding.com)
|
||||||
|
* @date Created in 2019-07-18 16:36
|
||||||
|
*/
|
||||||
|
public class UrlBuilderTest {
|
||||||
|
@Test
|
||||||
|
public void testUrlBuilder() {
|
||||||
|
AuthConfig config = AuthConfig.builder()
|
||||||
|
.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"))
|
||||||
|
.build(false);
|
||||||
|
AuthWeChatRequest request = new AuthWeChatRequest(config);
|
||||||
|
String authorize = request.authorize();
|
||||||
|
Assert.assertEquals(build, authorize);
|
||||||
|
AuthState.delete(AuthSource.WECHAT);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,19 +1,107 @@
|
|||||||
### 2019/05/24
|
### 2019/07/22 ([v1.9.2](https://gitee.com/yadong.zhang/JustAuth/releases/v1.9.2))
|
||||||
|
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) 直接使用
|
||||||
|
|
||||||
|
### 2019/07/22 ([v1.9.1](https://gitee.com/yadong.zhang/JustAuth/releases/v1.9.1))
|
||||||
|
1. 增加`stackoverflow`参数校验
|
||||||
|
2. 解决`Pinterest`获取用户失败的问题
|
||||||
|
3. 添加注释
|
||||||
|
|
||||||
|
### 2019/07/19 ([v1.9.0](https://gitee.com/yadong.zhang/JustAuth/releases/v1.9.0))
|
||||||
|
|
||||||
|
1. 合并github上[@dyc12ii](https://github.com/dyc12ii) 的[pr#25](https://github.com/zhangyd-c/JustAuth/pull/25),升级fastjson版本至1.2.58,避免安全漏洞
|
||||||
|
2. `AuthUserGender`枚举类挪到`enums`包下
|
||||||
|
3. 删除`AuthBaiduErrorCode`和`AuthDingTalkErrorCode`枚举类
|
||||||
|
4. 优化百度授权流程,增加refresh token的方法
|
||||||
|
5. 优化`AuthConfig`、`AuthResponse`类,去掉不必要的lombonk注解,减少编译后的代码量
|
||||||
|
6. 使用lombok注解优化枚举类
|
||||||
|
7. `AuthQqRequest`增加refresh方法
|
||||||
|
8. 修复google登录无法获取用户信息的问题
|
||||||
|
9. 优化代码
|
||||||
|
|
||||||
|
### 2019/07/18
|
||||||
|
|
||||||
|
1. 合并github上[@pengisgood](https://github.com/pengisgood) 的[pr#19](https://github.com/zhangyd-c/JustAuth/pull/19),集成人人
|
||||||
|
2. 合并github上[@pengisgood](https://github.com/pengisgood) 的[pr#20](https://github.com/zhangyd-c/JustAuth/pull/20),集成Pinterest
|
||||||
|
3. 合并github上[@pengisgood](https://github.com/pengisgood) 的[pr#21](https://github.com/zhangyd-c/JustAuth/pull/21),集成StackOverflow
|
||||||
|
4. 合并github上[@xkcoding](https://github.com/xkcoding) 的[pr#23](https://github.com/zhangyd-c/JustAuth/pull/23),重构代码、新增编辑器规范,规范PR代码风格
|
||||||
|
|
||||||
|
### 2019/07/17
|
||||||
|
1. 优化代码
|
||||||
|
2. 集成Teambition登录
|
||||||
|
|
||||||
|
### 2019/07/16
|
||||||
|
1. 重构UrlBuilder类
|
||||||
|
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),修复小米回调错误问题 同时 支持微信获取
|
||||||
|
|
||||||
|
### 2019/07/15 ([v1.8.1](https://gitee.com/yadong.zhang/JustAuth/releases/v1.8.1))
|
||||||
|
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](https://gitee.com/yadong.zhang/JustAuth/releases/v1.8.0))
|
||||||
|
1. 修复百度登录获取不到token失效时间的问题
|
||||||
|
2. 增加state参数校验,预防CSRF。**强烈建议启用state**!
|
||||||
|
|
||||||
|
### 2019/06/27
|
||||||
|
1. 修复百度登录获取不到token失效时间的问题
|
||||||
|
2. 增加state参数校验,预防CSRF。**强烈建议启用state**!
|
||||||
|
3. 修改login方法的参数为AuthCallback,封装回调返回的参数
|
||||||
|
4. 支持state参数
|
||||||
|
5. 增加code和state参数校验
|
||||||
|
|
||||||
|
由于state安全问题,1.8.0以前的版本都有隐藏的CSRF漏洞问题,所以强烈建议正在使用JustAuth的朋友升级到1.8.0版本!
|
||||||
|
|
||||||
|
### 2019/06/25 ([v1.7.1](https://gitee.com/yadong.zhang/JustAuth/releases/v1.7.1))
|
||||||
|
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](https://gitee.com/yadong.zhang/JustAuth/releases/v1.7.0))
|
||||||
|
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](https://gitee.com/yadong.zhang/JustAuth/releases/v1.6.1-beta))
|
||||||
|
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)
|
||||||
|
4. 修复部分注释、拼写错误
|
||||||
|
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](https://gitee.com/yadong.zhang/JustAuth/releases/v1.6.0-beta))
|
||||||
|
1. 增加今日头条的授权登陆
|
||||||
|
2. 发布1.6.0-beta版本,今日头条开发者暂时不能认证, 所以无法做测试,等测试通过后,正式发布release版本
|
||||||
|
|
||||||
|
### 2019/05/28 ([v1.5.0](https://gitee.com/yadong.zhang/JustAuth/releases/v1.5.0))
|
||||||
|
1. 增加小米账号和微软的授权登陆
|
||||||
|
2. 发布1.5.0版本
|
||||||
|
|
||||||
|
### 2019/05/26 ([v1.4.0](https://gitee.com/yadong.zhang/JustAuth/releases/v1.4.0))
|
||||||
|
1. 增加抖音和Linkedin的授权登陆
|
||||||
|
2. 修改部分图片命名
|
||||||
|
3. 优化部分代码
|
||||||
|
4. 修复`AuthSource`中腾讯云开发平台的拼写错误:`TENCEN_CLOUD`->`TENCENT_CLOUD`
|
||||||
|
5. 修复支付宝登陆时用户名为空的问题
|
||||||
|
|
||||||
|
|
||||||
|
### 2019/05/24 ([v1.3.3](https://gitee.com/yadong.zhang/JustAuth/releases/v1.3.3))
|
||||||
1. 修复一些问题
|
1. 修复一些问题
|
||||||
2. 升级api,在AuthUser中增加`uuid`属性,可以通过`uuid` + `source`唯一确定一个用户,此举解决了用户身份归属的问题。
|
2. 升级api,在AuthUser中增加`uuid`属性,可以通过`uuid` + `source`唯一确定一个用户,此举解决了用户身份归属的问题。
|
||||||
3. 发布1.3.3版本的jar包到公开仓库(1.3.2忘记发布了,( ╯□╰ ))
|
3. 发布1.3.3版本的jar包到公开仓库(1.3.2忘记发布了,( ╯□╰ ))
|
||||||
4. 重要:经咨询官方客服得知,CSDN的授权开放平台已经下线,如果以前申请过的应用,可以继续使用,但是不再支持申请新的应用。so, 本项目中的CSDN登录只能针对少部分用户使用了
|
4. 重要:经咨询官方客服得知,CSDN的授权开放平台已经下线,如果以前申请过的应用,可以继续使用,但是不再支持申请新的应用。so, 本项目中的CSDN登录只能针对少部分用户使用了
|
||||||
|
|
||||||
### 2019/05/23
|
### 2019/05/23 ([v1.3.1](https://gitee.com/yadong.zhang/JustAuth/releases/v1.3.1))
|
||||||
1. 修复QQ登录的问题
|
1. 修复QQ登录的问题
|
||||||
2. 发布1.3.1版本的jar包到公开仓库
|
2. 发布1.3.1版本的jar包到公开仓库
|
||||||
|
|
||||||
### 2019/05/21
|
### 2019/05/21 ([v1.3.0](https://gitee.com/yadong.zhang/JustAuth/releases/v1.3.0))
|
||||||
1. 新增google授权登录
|
1. 新增google授权登录
|
||||||
2. 新增facebook授权登录
|
2. 新增facebook授权登录
|
||||||
3. 发布1.3.0版本的jar包到公开仓库
|
3. 发布1.3.0版本的jar包到公开仓库
|
||||||
|
|
||||||
### 2019/05/18
|
### 2019/05/18 ([v1.1.0](https://gitee.com/yadong.zhang/JustAuth/releases/v1.1.0) | [v1.2.0](https://gitee.com/yadong.zhang/JustAuth/releases/v1.2.0))
|
||||||
1. 发布1.1.0版本的jar包到公开仓库(支持qq和微信登录)
|
1. 发布1.1.0版本的jar包到公开仓库(支持qq和微信登录)
|
||||||
2. 支持淘宝登录
|
2. 支持淘宝登录
|
||||||
3. 修改`AuthUser.java`类中的`accessToken`属性,由原本的~~accessToken (String)~~改为`token (AuthToken)`
|
3. 修改`AuthUser.java`类中的`accessToken`属性,由原本的~~accessToken (String)~~改为`token (AuthToken)`
|
||||||
@@ -22,4 +110,10 @@
|
|||||||
|
|
||||||
### 2019/05/17
|
### 2019/05/17
|
||||||
1. 增加qq和微信的授权登录
|
1. 增加qq和微信的授权登录
|
||||||
2. 修改getAccessToken方法的返回值
|
2. 修改getAccessToken方法的返回值
|
||||||
|
|
||||||
|
### 2019/03/27 ([v1.0.1](https://gitee.com/yadong.zhang/JustAuth/releases/v1.0.1))
|
||||||
|
集成 支付宝授权登录
|
||||||
|
|
||||||
|
### 2019/03/25 ([v1.0.0](https://gitee.com/yadong.zhang/JustAuth/releases/v1.0.0))
|
||||||
|
史上最全的整合第三方登录的工具,目前已支持Github、Gitee、微博、钉钉和百度、Coding、腾讯云开发者平台和OSChina登录。 Login, so easy!
|
||||||
Reference in New Issue
Block a user