Compare commits
111 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 80132b69e7 | |||
| 95158654a9 | |||
| f2e609192a | |||
| 8c8f7a27a2 | |||
| 8283124c57 | |||
| 39b113b194 | |||
| e45ef2ec31 | |||
| d114368a0d | |||
| 0047cde50e | |||
| f2c1c0f8a6 | |||
| 21e23aadb9 | |||
| db3f7da181 | |||
| 004e5a180f | |||
| 50c31e5dea | |||
| 7d6049da67 | |||
| 9a24553acd | |||
| d75d91db0d | |||
| e1a4688ac0 | |||
| b1d3790ae1 | |||
| e5548b0173 | |||
| ebf39627dd | |||
| 74ee17b242 | |||
| b77de0bd0c | |||
| e55033f4f5 | |||
| 37b7784f89 | |||
| 7cdc719166 | |||
| 5073f82897 | |||
| 9971793f0c | |||
| 9fc3131640 | |||
| 3f4436bcb6 | |||
| 0678202baa | |||
| af8fda700b | |||
| 881a87ed95 | |||
| 4c8fdbae49 | |||
| e8db2dd282 | |||
| 90374762e4 | |||
| e5d44e91b8 | |||
| 41559fc954 | |||
| d354278e7d | |||
| c2d6661a76 | |||
| 5ee87760be | |||
| 94f6540338 | |||
| 7bc7a92efb | |||
| b5920872d5 | |||
| 0bdf881849 | |||
| 46f7c72744 | |||
| 4a662ba5cd | |||
| 040587d5b2 | |||
| c81411fd39 | |||
| 0e1b000bd8 | |||
| f9b30c735b | |||
| 0f42457d91 | |||
| fa75568996 | |||
| f44ceeeeeb | |||
| ec4c009ed8 | |||
| 03fbbe0d3a | |||
| e64e9def63 | |||
| 25f99f7560 | |||
| 0433f54564 | |||
| 423d9f45b6 | |||
| 7a9e6214de | |||
| 3753e3b9bc | |||
| bc3af96328 | |||
| b700902c04 | |||
| 2d0ae7cc27 | |||
| 3e4faa75fe | |||
| 6a36ad6af2 | |||
| 13514d6a92 | |||
| 6a479d9c1d | |||
| 2e64fb9693 | |||
| 0e8308e6c9 | |||
| 3933b3b7ee | |||
| a99b818810 | |||
| cd324cc7c1 | |||
| 3e890f2c2a | |||
| ba56f5ab5a | |||
| 132a7f4338 | |||
| c79b97a0d0 | |||
| 66df3ac027 | |||
| 11df93ad44 | |||
| e3f5f49ec8 | |||
| 23eb2cfcc8 | |||
| 30461e62f9 | |||
| dfbbd9ae0d | |||
| 05b7746f26 | |||
| 21422b02aa | |||
| 10e445e87c | |||
| d6cbcecaab | |||
| 050459e616 | |||
| 9fd2b9b919 | |||
| 2ff5570399 | |||
| 1bec384525 | |||
| 824c68356d | |||
| f5e3c225f6 | |||
| 0259669288 | |||
| edc9d1a3c3 | |||
| d886bc95a2 | |||
| 7aaf52e953 | |||
| e84bd7cdb5 | |||
| 28e19960f2 | |||
| dce2bd1e1e | |||
| bc30971482 | |||
| 9bd6d88049 | |||
| 442332be57 | |||
| d4bfa8e75f | |||
| fb90fbdcb8 | |||
| 5f6cb2954f | |||
| 906ae659a2 | |||
| cebfd99703 | |||
| 71b6080156 | |||
| 492ffdbbf8 |
@@ -10,7 +10,7 @@ assignees: ''
|
||||
|
||||
- [ ] I have searched the relevant information in the existing list of Issues.
|
||||
- [ ] I have searched the developer documentation for that information: https://justauth.wiki
|
||||
- [ ] I have read the relevant Q&A: https://justauth.wiki/#/Q&A
|
||||
- [ ] I have read the relevant Q&A: https://justauth.wiki
|
||||
|
||||
## Issue description
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
name: Deploy SNAPSHOT
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ dev ]
|
||||
paths:
|
||||
- src/**
|
||||
- pom.xml
|
||||
pull_request:
|
||||
branches: [ dev ]
|
||||
paths:
|
||||
- src/**
|
||||
- pom.xml
|
||||
|
||||
jobs:
|
||||
get-latest-tag:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2.2.0
|
||||
- name: Set up Java and Maven
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: '8'
|
||||
distribution: 'adopt'
|
||||
server-id: ossrh
|
||||
server-username: MAVEN_USERNAME
|
||||
server-password: MAVEN_PASSWORD
|
||||
- name: Cache m2 package
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('pom.xml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-maven-
|
||||
- name: get current project version to set env.VERSION
|
||||
run: echo "VERSION=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout`" >> $GITHUB_ENV
|
||||
- name: set snapshot version
|
||||
if: ${{ !endsWith( env.VERSION , '-SNAPSHOT') }}
|
||||
run: mvn versions:set -DnewVersion=${{ env.VERSION }}-SNAPSHOT
|
||||
- name: deploy snapshot to ossrh repository
|
||||
run: mvn -B deploy -P snapshot
|
||||
env:
|
||||
MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
|
||||
MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
|
||||
@@ -28,8 +28,6 @@ hs_err_pid*
|
||||
bin/codecov.sh
|
||||
bin/deploy.sh
|
||||
bin/docsify-cli.sh
|
||||
bin/push.sh
|
||||
bin/push-dev.sh
|
||||
|
||||
target
|
||||
/pom.xml.versionsBackup
|
||||
|
||||
@@ -1,3 +1,102 @@
|
||||
## 1.16.3
|
||||
|
||||
### 2021/8/15
|
||||
|
||||
- 发布 v1.16.3
|
||||
- 新增
|
||||
- 集成“企业微信的第三方应用”平台登录
|
||||
- PR
|
||||
- `AuthRequst` 增加 `Builder` 构建方式,使用起来更简单。 ([#27](https://gitee.com/yadong.zhang/JustAuth/pulls/27))
|
||||
- 使用 Github Action 添加发布快照的 workflow。 ([#126](https://github.com/justauth/JustAuth/pull/126))
|
||||
- 新增了企业微信的第三方应用登录,`AuthWeChatEnterpriseThirdQrcodeRequest`。 ([#127](https://github.com/justauth/JustAuth/pull/127))
|
||||
- 添加快照版本对应更详细的文档。 ([#128](https://github.com/justauth/JustAuth/pull/128))
|
||||
- 修改
|
||||
- 在 Gitee PR ([#27](https://gitee.com/yadong.zhang/JustAuth/pulls/27)) 的基础上重构代码,增加 Builder 方式创建 AuthRequest
|
||||
- 解决 Line 登录的错误。[#122](https://github.com/justauth/JustAuth/issues/122)
|
||||
|
||||
|
||||
## 1.16.2
|
||||
|
||||
### 2021/7/28
|
||||
|
||||
- 发布 v1.16.2
|
||||
- 新增
|
||||
- 集成“程序员客栈”平台登录
|
||||
- 修改
|
||||
- 更新文档
|
||||
- 修复“淘宝”平台授权登录后没有`uid`的问题、增加刷新token的功能
|
||||
- 修复“Twitter”平台授权登录后获取不到用户邮箱的问题
|
||||
|
||||
## 1.16.1
|
||||
|
||||
### 2021/4/19
|
||||
|
||||
- 发布 v1.16.1
|
||||
- Fix Github issue [#114](https://github.com/justauth/JustAuth/issues/114): 解决企业微信授权后,回调地址中原有的参数丢失的问题
|
||||
- Fix Github issue [#82](https://github.com/justauth/JustAuth/issues/82): 抖音平台支持自定义 scope
|
||||
- Fix Github issue [#92](https://github.com/justauth/JustAuth/issues/92): 增加忽略校验 redirectUri 的配置
|
||||
- Merge Github PR [#115](https://github.com/justauth/JustAuth/pull/115)
|
||||
- 升级 `fastjson` 到 `v1.2.76`
|
||||
|
||||
## 1.16.0
|
||||
|
||||
### 2021/4/7
|
||||
|
||||
- 发布 v1.16.0
|
||||
- 新增
|
||||
- 集成 Amazon 平台登录
|
||||
- 集成 Slack 平台登录
|
||||
- 集成 LINE 平台登录
|
||||
- 集成 Okta 平台登录
|
||||
- 集成钉钉账号登录
|
||||
- 修改
|
||||
- 【**重要**】 `AuthConfig`中的`codingGroupName`参数更名为`domainPrefix`,针对此类平台提供通用的配置。
|
||||
- 修改 `AuthFacebookScope` 中的默认 scope,解决 justauth-demo 项目中使用 facebook 报错的问题
|
||||
- 升级 facebook 的 api 到 v10.0 版本
|
||||
- 优化部分代码
|
||||
- 优化 Map 声明时的初始容量,避免频繁扩容
|
||||
- 更新 README 文档
|
||||
- PR
|
||||
- 合并 [Github #110](https://github.com/justauth/JustAuth/pull/110)
|
||||
- 合并 [Gitee #22](https://gitee.com/yadong.zhang/JustAuth/pulls/22)
|
||||
|
||||
## 1.15.9
|
||||
|
||||
### 2021/1/1
|
||||
|
||||
- 发布 v1.15.9
|
||||
- 新增
|
||||
- 修复并正式启用 飞书 平台的第三方登录
|
||||
- AuthToken 类中新增 `refreshTokenExpireIn` 记录 refresh token 的有效期
|
||||
- PR
|
||||
- 合并 [Github #101](https://github.com/justauth/JustAuth/pull/101) :支持喜马拉雅登录
|
||||
- 合并 [Github #105](https://github.com/justauth/JustAuth/pull/105) :支持企业微信网页授权登录
|
||||
- 合并 [Github #107](https://github.com/justauth/JustAuth/pull/107) :添加AuthAlipayRequest网络代理构造器,解决 Github Issue [#102](https://github.com/justauth/JustAuth/issues/102)
|
||||
- 修改
|
||||
- 修改喜马拉雅配置参数,将`ClientOsType`参数提到 AuthConfig 中
|
||||
- AuthChecker 中增加对喜马拉雅平台的校验
|
||||
- 升级 facebook api 版本到 v9.0,解决 Gitee Issue [#I2AR5S](https://gitee.com/yadong.zhang/JustAuth/issues/I2AR5S)
|
||||
- !!!**注意**!!!修改原来的企业微信 Request 类名为 `AuthWeChatEnterpriseQrcodeRequest`,升级后注意该点
|
||||
|
||||
注意:可能有些开发者对于 JA 集成的四个微信平台不太理解,这儿统一说明:
|
||||
- 按照类名
|
||||
- AuthWeChatEnterpriseQrcodeRequest:企业微信二维码登录
|
||||
- AuthWeChatEnterpriseWebRequest:企业微信网页登录
|
||||
- AuthWeChatOpenRequest:微信开放平台
|
||||
- AuthWeChatMpRequest:微信公众平台
|
||||
- 按照枚举
|
||||
- WECHAT_ENTERPRISE:企业微信二维码登录
|
||||
- WECHAT_ENTERPRISE_WEB:企业微信网页登录
|
||||
- WECHAT_OPEN:微信开放平台
|
||||
- WECHAT_MP:微信公众平台
|
||||
|
||||
## 1.15.8
|
||||
|
||||
### 2020/10/25
|
||||
|
||||
- Release version 1.15.8
|
||||
- Merge the pr. [#95](https://github.com/justauth/JustAuth/pull/95) [#96](https://github.com/justauth/JustAuth/pull/96)
|
||||
|
||||
## 1.15.7
|
||||
|
||||
### 2020/09/11
|
||||
|
||||
+86
-68
@@ -6,7 +6,10 @@
|
||||
</p>
|
||||
<p align="center">
|
||||
<a target="_blank" href="https://search.maven.org/search?q=JustAuth">
|
||||
<img src="https://img.shields.io/badge/Maven%20Central-1.15.7-blue" ></img>
|
||||
<img src="https://img.shields.io/github/v/release/justauth/JustAuth?style=flat-square" ></img>
|
||||
</a>
|
||||
<a target="_blank" href="https://oss.sonatype.org/content/repositories/snapshots/me/zhyd/oauth/JustAuth/">
|
||||
<img src="https://img.shields.io/nexus/s/https/oss.sonatype.org/me.zhyd.oauth/JustAuth.svg?style=flat-square" ></img>
|
||||
</a>
|
||||
<a target="_blank" href="https://gitee.com/yadong.zhang/JustAuth/blob/master/LICENSE">
|
||||
<img src="https://img.shields.io/apm/l/vim-mode.svg?color=yellow" ></img>
|
||||
@@ -14,65 +17,24 @@
|
||||
<a target="_blank" href="https://www.oracle.com/technetwork/java/javase/downloads/index.html">
|
||||
<img src="https://img.shields.io/badge/JDK-1.8+-green.svg" ></img>
|
||||
</a>
|
||||
<a target="_blank" href="https://apidoc.gitee.com/yadong.zhang/JustAuth/" title="API文档">
|
||||
<img src="https://img.shields.io/badge/Api%20Docs-1.15.7-orange" ></img>
|
||||
</a>
|
||||
<a target="_blank" href="https://justauth.wiki" title="参考文档">
|
||||
<img src="https://img.shields.io/badge/Docs-latest-blueviolet.svg" ></img>
|
||||
</a>
|
||||
<a href="https://codecov.io/gh/zhangyd-c/JustAuth">
|
||||
<img src="https://codecov.io/gh/zhangyd-c/JustAuth/branch/master/graph/badge.svg" />
|
||||
<a href="https://codecov.io/gh/justauth/JustAuth">
|
||||
<img src="https://codecov.io/gh/justauth/JustAuth/branch/master/graph/badge.svg?token=zYiAqd9aFz" />
|
||||
</a>
|
||||
<a href='https://gitee.com/yadong.zhang/JustAuth/stargazers'>
|
||||
<img src='https://gitee.com/yadong.zhang/JustAuth/badge/star.svg?theme=white' alt='star'></img>
|
||||
<img src='https://gitee.com/yadong.zhang/JustAuth/badge/star.svg?theme=gvp' alt='star'></img>
|
||||
</a>
|
||||
<a target="_blank" href='https://github.com/zhangyd-c/JustAuth'>
|
||||
<img src="https://img.shields.io/github/stars/zhangyd-c/JustAuth.svg?style=social" alt="github star"></img>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<center>
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/gitee.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/github.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/weibo.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/dingtalk.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/baidu.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/coding.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/tencentCloud.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/oschina.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/alipay.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/qq.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/wechat.png" width="20" title="微信开放平台"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/taobao.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/google.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/facebook.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/douyin.png" width="20"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/linkedin.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/microsoft.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/mi.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/toutiao.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/teambition.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/renren.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/pinterest.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/stackoverflow.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/huawei.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/wechat.png" width="20" title="微信企业版"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/csdn.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/kujiale.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/gitlab.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/meituan.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/eleme.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/twitter.png" width="20"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<center><a href="https://justauth.wiki/#/?id=%E5%B7%B2%E9%9B%86%E6%88%90%E7%9A%84%E5%B9%B3%E5%8F%B0" target="_blank">查看更多</a></center>
|
||||
</center>
|
||||
-------------------------------------------------------------------------------
|
||||
<p align="center">
|
||||
<img src='./docs/media/75a3c076.png' alt='star'></img>
|
||||
</p>
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
@@ -90,34 +52,28 @@ Docs:[Reference Doc](https://justauth.wiki)
|
||||
|
||||
## Quick start
|
||||
|
||||
- Add maven dependency
|
||||
### Add maven dependency
|
||||
|
||||
- Add JustAuth dependency
|
||||
|
||||
These artifacts are available from Maven Central:
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>me.zhyd.oauth</groupId>
|
||||
<artifactId>JustAuth</artifactId>
|
||||
<version>1.15.7-beta.2</version>
|
||||
<version>{latest-version}</version>
|
||||
</dependency>
|
||||
```
|
||||
- Using JustAuth
|
||||
```java
|
||||
// Create authorization request
|
||||
AuthRequest authRequest = new AuthGiteeRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.build());
|
||||
// Generate authorization url
|
||||
authRequest.authorize("state");
|
||||
// After authorization to login, it will return: code(auth_code(Alipay only)),state, After version 1.8.0, you can use the AuthCallback as a parameter to the callback interface
|
||||
// Note: JustAuth saves state for 3 minutes by default. If it is not used within 3 minutes, the expired state will be cleared automatically.
|
||||
authRequest.login(callback);
|
||||
```
|
||||
|
||||
Note, that since [v1.14.0](https://gitee.com/yadong.zhang/JustAuth/releases/v1.14.0) JustAuth has been integrated by default with [simple-http](https://github.com/xkcoding/simple-http) as the HTTP general interface (see the update [JustAuth 1.14.0 release! Perfect decoupling of HTTP tools](https://mp.weixin.qq.com/s?__biz=MzA3NDk3OTIwMg==&mid=2450633197&idx=1&sn=11e625b307db62b2f1c4e82f7744b2a2&chksm=88929300bfe51a16562b45592a264482ae2c74c6dbfa4a3aa9611ad4fea4a9be5b1f0545527d&token=1093833287&lang=zh_CN#rd)). Since most projects already integrate HTTP tools such as OkHttp3, apache HttpClient, and hutool-http), in order to reduce unnecessary dependencies,Starting from [v1.14.0](https://gitee.com/yadong.zhang/JustAuth/releases/v1.14.0), JustAuth will not integrate hutool-http by default. If the developer's project is new or there is no integrated HTTP implementation tool in the project, please add the corresponding HTTP implementation class by yourself. Alternative dependencies are as follows:
|
||||
> **latest-version** :
|
||||
> - CURRENT: 
|
||||
> - SNAPSHOT: 
|
||||
|
||||
|
||||
- Add http dependency(Only need one)
|
||||
|
||||
> If there is already in the project, please ignore it. In addition, you need to pay special attention. If the low version of the dependency has been introduced in the project, please exclude the low version of the dependency first, and then introduce the high version or the latest version of the dependency
|
||||
|
||||
- hutool-http
|
||||
|
||||
```xml
|
||||
@@ -148,6 +104,68 @@ Note, that since [v1.14.0](https://gitee.com/yadong.zhang/JustAuth/releases/v1.1
|
||||
</dependency>
|
||||
```
|
||||
|
||||
|
||||
### Using JustAuth API
|
||||
|
||||
#### Simple
|
||||
|
||||
```java
|
||||
// Create authorization request
|
||||
AuthRequest authRequest = new AuthGiteeRequest(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.build());
|
||||
// Generate authorization page url
|
||||
authRequest.authorize("state");
|
||||
// Get token and userinfo
|
||||
authRequest.login(callback);
|
||||
```
|
||||
|
||||
#### Builder 1. Use unchanging `AuthConfig`
|
||||
|
||||
```java
|
||||
// Create authorization request
|
||||
AuthRequest authRequest = AuthRequestBuilder.builder()
|
||||
.source("github")
|
||||
.authConfig(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.build())
|
||||
.build();
|
||||
```
|
||||
|
||||
#### Builder 2. Use dynamic `AuthConfig`
|
||||
|
||||
```java
|
||||
// Create authorization request
|
||||
AuthRequest authRequest = AuthRequestBuilder.builder()
|
||||
.source("gitee")
|
||||
.authConfig((source) -> {
|
||||
// Use source to dynamically get AuthConfig
|
||||
// Here you can flexibly take the configuration from sql or take the configuration from the configuration file
|
||||
return AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.build();
|
||||
})
|
||||
.build();
|
||||
```
|
||||
|
||||
#### Builder 3. Support custom platform
|
||||
|
||||
```java
|
||||
AuthRequest authRequest = AuthRequestBuilder.builder()
|
||||
// Key point: configure the custom implementation of AuthSource
|
||||
.extendSource(AuthExtendSource.values())
|
||||
// Enum name in AuthExtendSource
|
||||
.source("other")
|
||||
// ... Do other things
|
||||
.build();
|
||||
```
|
||||
|
||||
## Contributions
|
||||
|
||||
1. Fork this project to your repository
|
||||
@@ -162,11 +180,11 @@ I look forward to your joining us.
|
||||
|
||||
## Contributors
|
||||
|
||||
[contributors](https://justauth.wiki/#/contributors)
|
||||
[contributors](https://justauth.wiki/contributors.html)
|
||||
|
||||
## Change Logs
|
||||
|
||||
[CHANGELOGS](https://justauth.wiki/#/update)
|
||||
[CHANGELOGS](https://justauth.wiki/update.html)
|
||||
|
||||
## Recommend
|
||||
|
||||
|
||||
@@ -6,7 +6,10 @@
|
||||
</p>
|
||||
<p align="center">
|
||||
<a target="_blank" href="https://search.maven.org/search?q=JustAuth">
|
||||
<img src="https://img.shields.io/badge/Maven%20Central-1.15.7-blue" ></img>
|
||||
<img src="https://img.shields.io/github/v/release/justauth/JustAuth?style=flat-square" ></img>
|
||||
</a>
|
||||
<a target="_blank" href="https://oss.sonatype.org/content/repositories/snapshots/me/zhyd/oauth/JustAuth/">
|
||||
<img src="https://img.shields.io/nexus/s/https/oss.sonatype.org/me.zhyd.oauth/JustAuth.svg?style=flat-square" ></img>
|
||||
</a>
|
||||
<a target="_blank" href="https://gitee.com/yadong.zhang/JustAuth/blob/master/LICENSE">
|
||||
<img src="https://img.shields.io/apm/l/vim-mode.svg?color=yellow" ></img>
|
||||
@@ -14,65 +17,24 @@
|
||||
<a target="_blank" href="https://www.oracle.com/technetwork/java/javase/downloads/index.html">
|
||||
<img src="https://img.shields.io/badge/JDK-1.8+-green.svg" ></img>
|
||||
</a>
|
||||
<a target="_blank" href="https://apidoc.gitee.com/yadong.zhang/JustAuth/" title="API文档">
|
||||
<img src="https://img.shields.io/badge/Api%20Docs-1.15.7-orange" ></img>
|
||||
</a>
|
||||
<a target="_blank" href="https://justauth.wiki" title="参考文档">
|
||||
<img src="https://img.shields.io/badge/Docs-latest-blueviolet.svg" ></img>
|
||||
</a>
|
||||
<a href="https://codecov.io/gh/zhangyd-c/JustAuth">
|
||||
<img src="https://codecov.io/gh/zhangyd-c/JustAuth/branch/master/graph/badge.svg" />
|
||||
<a href="https://codecov.io/gh/justauth/JustAuth">
|
||||
<img src="https://codecov.io/gh/justauth/JustAuth/branch/master/graph/badge.svg?token=zYiAqd9aFz" />
|
||||
</a>
|
||||
<a href='https://gitee.com/yadong.zhang/JustAuth/stargazers'>
|
||||
<img src='https://gitee.com/yadong.zhang/JustAuth/badge/star.svg?theme=white' alt='star'></img>
|
||||
<img src='https://gitee.com/yadong.zhang/JustAuth/badge/star.svg?theme=gvp' alt='star'></img>
|
||||
</a>
|
||||
<a target="_blank" href='https://github.com/zhangyd-c/JustAuth'>
|
||||
<img src="https://img.shields.io/github/stars/zhangyd-c/JustAuth.svg?style=social" alt="github star"></img>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<center>
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/gitee.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/github.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/weibo.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/dingtalk.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/baidu.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/coding.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/tencentCloud.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/oschina.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/alipay.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/qq.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/wechat.png" width="20" title="微信开放平台"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/taobao.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/google.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/facebook.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/douyin.png" width="20"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/linkedin.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/microsoft.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/mi.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/toutiao.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/teambition.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/renren.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/pinterest.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/stackoverflow.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/huawei.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/wechat.png" width="20" title="微信企业版"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/csdn.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/kujiale.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/gitlab.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/meituan.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/eleme.png" width="20"></td>
|
||||
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/twitter.png" width="20"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<center><a href="https://justauth.wiki/#/?id=%E5%B7%B2%E9%9B%86%E6%88%90%E7%9A%84%E5%B9%B3%E5%8F%B0" target="_blank">查看更多</a></center>
|
||||
</center>
|
||||
-------------------------------------------------------------------------------
|
||||
<p align="center">
|
||||
<img src='./docs/media/75a3c076.png' alt='star'></img>
|
||||
</p>
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
@@ -84,7 +46,7 @@ QQ 群:230017570
|
||||
|
||||
JustAuth,如你所见,它仅仅是一个**第三方授权登录**的**工具类库**,它可以让我们脱离繁琐的第三方登录 SDK,让登录变得**So easy!**
|
||||
|
||||
JustAuth 集成了诸如:Github、Gitee、支付宝、新浪微博、微信、Google、Facebook、Twitter、StackOverflow等国内外数十家第三方平台。更多请参考<a href="https://justauth.wiki/#/?id=%E5%B7%B2%E9%9B%86%E6%88%90%E7%9A%84%E5%B9%B3%E5%8F%B0" target="_blank">已集成的平台</a>
|
||||
JustAuth 集成了诸如:Github、Gitee、支付宝、新浪微博、微信、Google、Facebook、Twitter、StackOverflow等国内外数十家第三方平台。更多请参考<a href="https://justauth.wiki" target="_blank">已集成的平台</a>
|
||||
|
||||
## 有哪些特点?
|
||||
|
||||
@@ -93,24 +55,94 @@ JustAuth 集成了诸如:Github、Gitee、支付宝、新浪微博、微信、
|
||||
|
||||
## 有哪些功能?
|
||||
|
||||
- 集成国内外数十家第三方平台,实现快速接入。<a href="https://justauth.wiki/#/?id=%E5%B7%B2%E9%9B%86%E6%88%90%E7%9A%84%E5%B9%B3%E5%8F%B0" target="_blank">参考文档</a>
|
||||
- 自定义 State 缓存,支持各种分布式缓存组件。<a href="https://justauth.wiki/#/customize-the-state-cache" target="_blank">参考文档</a>
|
||||
- 自定义 OAuth 平台,更容易适配自有的 OAuth 服务。<a href="https://justauth.wiki/#/customize-the-oauth" target="_blank">参考文档</a>
|
||||
- 自定义 Http 实现,选择权完全交给开发者,不会单独依赖某一具体实现。<a href="https://justauth.wiki/#/customize-the-oauth" target="_blank">参考文档</a>
|
||||
- 自定义 Scope,支持更完善的授权体系。<a href="https://justauth.wiki" target="_blank">参考文档</a>
|
||||
- 集成国内外数十家第三方平台,实现快速接入。<a href="https://justauth.wiki/quickstart/how-to-use.html" target="_blank">参考文档</a>
|
||||
- 自定义 State 缓存,支持各种分布式缓存组件。<a href="https://justauth.wiki/features/customize-the-state-cache.html" target="_blank">参考文档</a>
|
||||
- 自定义 OAuth 平台,更容易适配自有的 OAuth 服务。<a href="https://justauth.wiki/features/customize-the-oauth.html" target="_blank">参考文档</a>
|
||||
- 自定义 Http 实现,选择权完全交给开发者,不会单独依赖某一具体实现。<a href="https://justauth.wiki/quickstart/how-to-use.html#%E4%BD%BF%E7%94%A8%E6%96%B9%E5%BC%8F" target="_blank">参考文档</a>
|
||||
- 自定义 Scope,支持更完善的授权体系。<a href="https://justauth.wiki/features/customize-scopes.html" target="_blank">参考文档</a>
|
||||
- 更多...<a href="https://justauth.wiki" target="_blank">参考文档</a>
|
||||
|
||||
## 快速开始
|
||||
|
||||
- 引入依赖
|
||||
### 引入依赖
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>me.zhyd.oauth</groupId>
|
||||
<artifactId>JustAuth</artifactId>
|
||||
<version>1.15.7</version>
|
||||
<version>{latest-version}</version>
|
||||
</dependency>
|
||||
```
|
||||
- 调用api
|
||||
|
||||
> **latest-version** 可选:
|
||||
> - 稳定版:
|
||||
> - 快照版:
|
||||
> > 注意:快照版本是功能的尝鲜,并不保证稳定性。请勿在生产环境中使用。
|
||||
>
|
||||
> <details>
|
||||
> <summary>如何引入快照版本</summary>
|
||||
>
|
||||
> JustAuth 的快照版本托管在 ossrh 上,所以要指定下载地址。
|
||||
>
|
||||
> ```xml
|
||||
> <repositories>
|
||||
> <repository>
|
||||
> <id>ossrh-snapshot</id>
|
||||
> <url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
> <snapshots>
|
||||
> <enabled>true</enabled>
|
||||
> </snapshots>
|
||||
> </repository>
|
||||
> </repositories>
|
||||
> ```
|
||||
>
|
||||
> 如果你想第一时间获取 JustAuth 的最新快照,可以添加下列代码,每次构建时都检查是否有最新的快照(默认每天检查)。
|
||||
>
|
||||
> ```diff
|
||||
> <url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
> <snapshots>
|
||||
> + <updatePolicy>always</updatePolicy>
|
||||
> <enabled>true</enabled>
|
||||
> </snapshots>
|
||||
> ```
|
||||
>
|
||||
> </details>
|
||||
|
||||
如下**任选一种** HTTP 工具 依赖,_项目内如果已有,请忽略。另外需要特别注意,如果项目中已经引入了低版本的依赖,请先排除低版本依赖后,再引入高版本或者最新版本的依赖_
|
||||
|
||||
- hutool-http
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-http</artifactId>
|
||||
<version>5.7.7</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
- httpclient
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.13</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
- okhttp
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>4.9.1</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### 调用api
|
||||
|
||||
#### 普通方式
|
||||
|
||||
```java
|
||||
// 创建授权request
|
||||
AuthRequest authRequest = new AuthGiteeRequest(AuthConfig.builder()
|
||||
@@ -125,60 +157,109 @@ authRequest.authorize("state");
|
||||
authRequest.login(callback);
|
||||
```
|
||||
|
||||
如下**任选一种** HTTP 工具 依赖,_项目内如果已有,请忽略。另外需要特别注意,如果项目中已经引入了低版本的依赖,请先排除低版本以后来,引入高版本或者最新版本的依赖_
|
||||
#### Builder 方式一
|
||||
|
||||
- hutool-http
|
||||
静态配置 `AuthConfig`
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-http</artifactId>
|
||||
<version>5.2.5</version>
|
||||
</dependency>
|
||||
```
|
||||
```java
|
||||
AuthRequest authRequest = AuthRequestBuilder.builder()
|
||||
.source("github")
|
||||
.authConfig(AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.build())
|
||||
.build();
|
||||
// 生成授权页面
|
||||
authRequest.authorize("state");
|
||||
// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的参数
|
||||
// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state
|
||||
authRequest.login(callback);
|
||||
```
|
||||
|
||||
- httpclient
|
||||
#### Builder 方式二
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.12</version>
|
||||
</dependency>
|
||||
```
|
||||
动态获取并配置 `AuthConfig`
|
||||
|
||||
- okhttp
|
||||
```java
|
||||
AuthRequest authRequest = AuthRequestBuilder.builder()
|
||||
.source("gitee")
|
||||
.authConfig((source) -> {
|
||||
// 通过 source 动态获取 AuthConfig
|
||||
// 此处可以灵活的从 sql 中取配置也可以从配置文件中取配置
|
||||
return AuthConfig.builder()
|
||||
.clientId("clientId")
|
||||
.clientSecret("clientSecret")
|
||||
.redirectUri("redirectUri")
|
||||
.build();
|
||||
})
|
||||
.build();
|
||||
Assert.assertTrue(authRequest instanceof AuthGiteeRequest);
|
||||
System.out.println(authRequest.authorize(AuthStateUtils.createState()));
|
||||
```
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>4.4.1</version>
|
||||
</dependency>
|
||||
```
|
||||
#### Builder 方式支持自定义的平台
|
||||
|
||||
```java
|
||||
AuthRequest authRequest = AuthRequestBuilder.builder()
|
||||
// 关键点:将自定义实现的 AuthSource 配置上
|
||||
.extendSource(AuthExtendSource.values())
|
||||
// source 对应 AuthExtendSource 中的枚举 name
|
||||
.source("other")
|
||||
// ... 其他内容不变,参考上面的示例
|
||||
.build();
|
||||
```
|
||||
|
||||
## 赞助和支持
|
||||
|
||||
感谢以下赞助商的支持:
|
||||
|
||||
[我要赞助](https://justauth.wiki/sponsor.html)
|
||||
|
||||
## JustAuth 的用户
|
||||
有很多公司、组织和个人把 JustAuth 用于学习、研究、生产环境和商业产品中,包括(但不限于):
|
||||

|
||||
|
||||
|
||||
怎么没有我?[加入]()
|
||||
怎么没有我?[登记](https://gitee.com/yadong.zhang/JustAuth/issues/IZ2T7)
|
||||
|
||||
## 开源推荐
|
||||
|
||||
- `JAP` 开源的登录认证中间件: [https://gitee.com/fujieid/jap](https://gitee.com/fujieid/jap)
|
||||
- `spring-boot-demo` 深度学习并实战 spring boot 的项目: [https://github.com/xkcoding/spring-boot-demo](https://github.com/xkcoding/spring-boot-demo)
|
||||
- `mica` SpringBoot 微服务高效开发工具集: [https://github.com/lets-mica/mica](https://github.com/lets-mica/mica)
|
||||
- `pig` 微服务认证授权脚手架(架构师必备): [https://gitee.com/log4j/pig](https://gitee.com/log4j/pig)
|
||||
- `SpringBlade` 完整的线上解决方案(企业开发必备): [https://gitee.com/smallc/SpringBlade](https://gitee.com/smallc/SpringBlade)
|
||||
- `MaxKey` 马克思的钥匙,寓意是最大钥匙,是用户单点登录认证系统(Sigle Sign On System),OAuth 2.0/OpenID Connect、SAML 2.0、JWT、CAS等标准化的开放协议,使用JustAuth集成OAuth第三方认证。: [https://shimingxy.github.io/MaxKey/](https://shimingxy.github.io/MaxKey/)
|
||||
- `YurunOAuthLogin` PHP 第三方登录授权 SDK:[YurunOAuthLogin](https://gitee.com/yurunsoft/YurunOAuthLogin)
|
||||
- `sureness` 面向restful api的高性能认证鉴权框架:[sureness](https://github.com/usthe/sureness)
|
||||
|
||||
更多推荐,请参考:[JustAuth - 开源推荐](https://justauth.wiki)
|
||||
|
||||
## 鸣谢
|
||||
|
||||
# 鸣谢
|
||||
- 感谢 JetBrains 提供的免费开源 License:
|
||||
<img src="https://images.gitee.com/uploads/images/2020/0406/220236_f5275c90_5531506.png" alt="图片引用自lets-mica" style="float:left;">
|
||||
|
||||
<a href="https://www.producthunt.com/posts/justauth?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-justauth" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=196886&theme=dark" alt="JustAuth - Login, so easy! | Product Hunt Embed" style="width: 250px; height: 54px;" width="250px" height="54px" /></a>
|
||||
<p>
|
||||
<img src="https://images.gitee.com/uploads/images/2020/0406/220236_f5275c90_5531506.png" alt="图片引用自lets-mica" style="float:left;">
|
||||
</p>
|
||||
|
||||
## 其他
|
||||
- [CONTRIBUTORS](https://justauth.wiki/#/contributors)
|
||||
- [CHANGELOGS](https://justauth.wiki/#/update)
|
||||
- [PLAN](https://gitee.com/yadong.zhang/JustAuth/issues/IUGRK)
|
||||
|
||||
- [CONTRIBUTORS](https://justauth.wiki/contributors.html)
|
||||
- [CHANGELOGS](https://justauth.wiki/update.html)
|
||||
- [PLAN](https://gitee.com/yadong.zhang/JustAuth/issues/IUGRK)
|
||||
|
||||
## 贡献者列表
|
||||
|
||||
[](https://whnb.wang)
|
||||
|
||||
## Stars 趋势
|
||||
|
||||
### Gitee
|
||||
|
||||
[](https://whnb.wang/yadong.zhang/JustAuth?e=604800)
|
||||
|
||||
### Github
|
||||
|
||||
[](https://starchart.cc/justauth/JustAuth)
|
||||
|
||||
### ProductHunt
|
||||
|
||||
<a href="https://www.producthunt.com/posts/justauth?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-justauth" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=196886&theme=dark" alt="JustAuth - Login, so easy! | Product Hunt Embed" style="width: 250px; height: 54px;" width="250px" height="54px" /></a>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
git pull origin dev && git pull github dev && git pull cc dev
|
||||
@@ -0,0 +1 @@
|
||||
git push origin dev && git push github dev && git push cc dev
|
||||
@@ -0,0 +1 @@
|
||||
git push origin master && git push github master && git push cc master
|
||||
@@ -25,8 +25,6 @@ fi
|
||||
# 替换README.md等文件中的版本
|
||||
sed -i "s/${old_version}/${new_version}/g" $pwd/README.md
|
||||
sed -i "s/${old_version}/${new_version}/g" $pwd/README.en-US.md
|
||||
sed -i "s/${old_version}/${new_version}/g" $pwd/docs/README.md
|
||||
sed -i "s/${old_version}/${new_version}/g" $pwd/docs/_coverpage.md
|
||||
|
||||
# 替换pom.xml中的版本
|
||||
sed -i "s/${old_version}/${new_version}/g" $pwd/pom.xml
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
1.15.7
|
||||
1.16.3
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 100 KiB |
@@ -15,6 +15,18 @@ case "$1" in
|
||||
'updv')
|
||||
bin/updVersion.sh $2
|
||||
;;
|
||||
'ppd')
|
||||
bin/pull-dev.sh
|
||||
;;
|
||||
'pd')
|
||||
bin/push-dev.sh
|
||||
;;
|
||||
'p')
|
||||
bin/push.sh
|
||||
;;
|
||||
'd')
|
||||
bin/deploy.sh
|
||||
;;
|
||||
*)
|
||||
help
|
||||
esac
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
|
||||
<groupId>me.zhyd.oauth</groupId>
|
||||
<artifactId>JustAuth</artifactId>
|
||||
<version>1.15.7</version>
|
||||
<version>1.16.3</version>
|
||||
|
||||
<name>JustAuth</name>
|
||||
<url>https://gitee.com/yadong.zhang/JustAuth</url>
|
||||
<description>
|
||||
小而全而美的第三方登录开源组件。目前已支持Github、Gitee、微博、钉钉、百度、Coding、腾讯云开发者平台、OSChina、支付宝、QQ、微信、淘宝、Google、Facebook、抖音、领英、小米、微软、今日头条、Teambition、StackOverflow、Pinterest、人人、华为、企业微信、酷家乐、Gitlab、美团、饿了么和推特等第三方平台的授权登录。 Login, so easy!
|
||||
小而全而美的第三方登录开源组件。目前已支持Github、Gitee、微博、钉钉、百度、Coding、腾讯云开发者平台、OSChina、支付宝、QQ、微信、淘宝、Google、Facebook、抖音、领英、小米、微软、今日头条、Teambition、StackOverflow、Pinterest、人人、华为、企业微信、酷家乐、Gitlab、美团、饿了么、推特、飞书、京东、阿里云、喜马拉雅、Amazon、Slack和Line等第三方平台的授权登录。 Login, so easy!
|
||||
</description>
|
||||
|
||||
<licenses>
|
||||
@@ -52,15 +52,15 @@
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<maven-source.version>2.2.1</maven-source.version>
|
||||
<maven-compiler.version>3.8.1</maven-compiler.version>
|
||||
<maven-javadoc.version>3.1.0</maven-javadoc.version>
|
||||
<maven-javadoc.version>2.9.1</maven-javadoc.version>
|
||||
<cobertura-version>2.7</cobertura-version>
|
||||
<maven-surefire-version>2.20</maven-surefire-version>
|
||||
<maven-gpg-version>1.6</maven-gpg-version>
|
||||
<maven.test.skip>false</maven.test.skip>
|
||||
<simple-http.version>1.0.2</simple-http.version>
|
||||
<simple-http.version>1.0.3</simple-http.version>
|
||||
<lombok-version>1.18.10</lombok-version>
|
||||
<junit-version>4.11</junit-version>
|
||||
<fastjson-version>1.2.73</fastjson-version>
|
||||
<junit-version>4.13.1</junit-version>
|
||||
<fastjson-version>1.2.76</fastjson-version>
|
||||
<alipay-sdk-version>4.8.10.ALL</alipay-sdk-version>
|
||||
<jacoco-version>0.8.2</jacoco-version>
|
||||
</properties>
|
||||
@@ -135,6 +135,9 @@
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<additionalparam>${javadoc.opts}</additionalparam>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
@@ -154,6 +157,15 @@
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>snapshot</id>
|
||||
<distributionManagement>
|
||||
<snapshotRepository>
|
||||
<id>ossrh</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<build>
|
||||
@@ -219,10 +231,6 @@
|
||||
</plugins>
|
||||
</build>
|
||||
<distributionManagement>
|
||||
<snapshotRepository>
|
||||
<id>sonatype-nexus-snapshots</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
</snapshotRepository>
|
||||
<repository>
|
||||
<id>sonatype-nexus-staging</id>
|
||||
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
|
||||
@@ -260,5 +268,15 @@
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
</profile>
|
||||
<!-- 禁用 Javadoc 注释检查 -->
|
||||
<profile>
|
||||
<id>disable-javadoc-doclint</id>
|
||||
<activation>
|
||||
<jdk>[1.8,)</jdk>
|
||||
</activation>
|
||||
<properties>
|
||||
<javadoc.opts>-Xdoclint:none</javadoc.opts>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
package me.zhyd.oauth;
|
||||
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthDefaultSource;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.request.AuthDefaultRequest;
|
||||
import me.zhyd.oauth.request.AuthRequest;
|
||||
import me.zhyd.oauth.utils.StringUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 快捷的构建 AuthRequest
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @author ngcly
|
||||
* @version 1.0.0
|
||||
* @since 1.16.3
|
||||
*/
|
||||
public class AuthRequestBuilder {
|
||||
private String source;
|
||||
private AuthConfig authConfig;
|
||||
private AuthStateCache authStateCache;
|
||||
private AuthSource[] extendSource;
|
||||
|
||||
private AuthRequestBuilder() {
|
||||
|
||||
}
|
||||
|
||||
public static AuthRequestBuilder builder() {
|
||||
return new AuthRequestBuilder();
|
||||
}
|
||||
|
||||
public AuthRequestBuilder source(String source) {
|
||||
this.source = source;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequestBuilder authConfig(AuthConfig authConfig) {
|
||||
this.authConfig = authConfig;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequestBuilder authConfig(Function<String, AuthConfig> authConfig) {
|
||||
this.authConfig = authConfig.apply(this.source);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequestBuilder authStateCache(AuthStateCache authStateCache) {
|
||||
this.authStateCache = authStateCache;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequestBuilder extendSource(AuthSource... extendSource) {
|
||||
this.extendSource = extendSource;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequest build() {
|
||||
if (StringUtils.isEmpty(this.source) || null == this.authConfig) {
|
||||
throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED);
|
||||
}
|
||||
// 合并 JustAuth 默认的 AuthDefaultSource 和 开发者自定义的 AuthSource
|
||||
AuthSource[] sources = this.concat(AuthDefaultSource.values(), extendSource);
|
||||
// 筛选符合条件的 AuthSource
|
||||
AuthSource source = Arrays.stream(sources).distinct()
|
||||
.filter(authSource -> authSource.getName().equalsIgnoreCase(this.source))
|
||||
.findAny()
|
||||
.orElseThrow(() -> new AuthException(AuthResponseStatus.NOT_IMPLEMENTED));
|
||||
|
||||
Class<? extends AuthDefaultRequest> targetClass = source.getTargetClass();
|
||||
if (null == targetClass) {
|
||||
throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED);
|
||||
}
|
||||
try {
|
||||
if (this.authStateCache == null) {
|
||||
return targetClass.getDeclaredConstructor(AuthConfig.class).newInstance(this.authConfig);
|
||||
} else {
|
||||
return targetClass.getDeclaredConstructor(AuthConfig.class, AuthStateCache.class).newInstance(this.authConfig, this.authStateCache);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED);
|
||||
}
|
||||
}
|
||||
|
||||
private AuthSource[] concat(AuthSource[] first, AuthSource[] second) {
|
||||
if (null == second || second.length == 0) {
|
||||
return first;
|
||||
}
|
||||
AuthSource[] result = new AuthSource[first.length + second.length];
|
||||
System.arraycopy(first, 0, result, 0, first.length);
|
||||
System.arraycopy(second, 0, result, first.length, second.length);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,8 +2,8 @@ package me.zhyd.oauth.config;
|
||||
|
||||
import com.xkcoding.http.config.HttpConfig;
|
||||
import lombok.*;
|
||||
import me.zhyd.oauth.enums.scope.AuthScope;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.utils.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -66,13 +66,24 @@ public class AuthConfig {
|
||||
private String agentId;
|
||||
|
||||
/**
|
||||
* 使用 Coding 登录时,需要传该值。
|
||||
* <p>
|
||||
* 团队域名前缀,比如以“ https://justauth.coding.net/ ”为例,{@code codingGroupName} = justauth
|
||||
* 企业微信第三方授权用户类型,member|admin
|
||||
*
|
||||
* @since 1.15.5
|
||||
* @since 1.10.0
|
||||
*/
|
||||
private String codingGroupName;
|
||||
private String usertype;
|
||||
|
||||
/**
|
||||
* 域名前缀。
|
||||
* <p>
|
||||
* 使用 Coding 登录和 Okta 登录时,需要传该值。
|
||||
* <p>
|
||||
* Coding 登录:团队域名前缀,比如以“ https://justauth.coding.net ”为例,{@code domainPrefix} = justauth
|
||||
* <p>
|
||||
* Okta 登录:Okta 账号域名前缀,比如以“ https://justauth.okta.com ”为例,{@code domainPrefix} = justauth
|
||||
*
|
||||
* @since 1.16.0
|
||||
*/
|
||||
private String domainPrefix;
|
||||
|
||||
/**
|
||||
* 针对国外服务可以单独设置代理
|
||||
@@ -110,4 +121,61 @@ public class AuthConfig {
|
||||
* @since 1.15.7
|
||||
*/
|
||||
private List<String> scopes;
|
||||
|
||||
/**
|
||||
* 设备ID, 设备唯一标识ID
|
||||
*
|
||||
* @since 1.15.8
|
||||
*/
|
||||
private String deviceId;
|
||||
|
||||
/**
|
||||
* 喜马拉雅:客户端操作系统类型,1-iOS系统,2-Android系统,3-Web
|
||||
*
|
||||
* @since 1.15.9
|
||||
*/
|
||||
private Integer clientOsType;
|
||||
|
||||
/**
|
||||
* 喜马拉雅:客户端包名,如果 {@link AuthConfig#clientOsType} 为1或2时必填。对Android客户端是包名,对IOS客户端是Bundle ID
|
||||
*
|
||||
* @since 1.15.9
|
||||
*/
|
||||
private String packId;
|
||||
|
||||
/**
|
||||
* 是否开启 PKCE 模式,该配置仅用于支持 PKCE 模式的平台,针对无服务应用,不推荐使用隐式授权,推荐使用 PKCE 模式
|
||||
*
|
||||
* @since 1.15.9
|
||||
*/
|
||||
private boolean pkce;
|
||||
|
||||
/**
|
||||
* Okta 授权服务器的 ID, 默认为 default。如果要使用自定义授权服务,此处传实际的授权服务器 ID(一个随机串)
|
||||
* <p>
|
||||
* 创建自定义授权服务器,请参考:
|
||||
* <p>
|
||||
* ① https://developer.okta.com/docs/concepts/auth-servers
|
||||
* <p>
|
||||
* ② https://developer.okta.com/docs/guides/customize-authz-server
|
||||
*
|
||||
* @since 1.16.0
|
||||
*/
|
||||
private String authServerId;
|
||||
/**
|
||||
* 忽略校验 {@code redirectUri} 参数,默认不开启。当 {@code ignoreCheckRedirectUri} 为 {@code true} 时,
|
||||
* {@link me.zhyd.oauth.utils.AuthChecker#checkConfig(AuthConfig, AuthSource)} 将不会校验 {@code redirectUri} 的合法性。
|
||||
*
|
||||
* @since 1.16.1
|
||||
*/
|
||||
private boolean ignoreCheckRedirectUri;
|
||||
|
||||
/**
|
||||
* 适配 builder 模式 set 值的情况
|
||||
*
|
||||
* @return authServerId
|
||||
*/
|
||||
public String getAuthServerId() {
|
||||
return StringUtils.isEmpty(authServerId) ? "default" : authServerId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package me.zhyd.oauth.config;
|
||||
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.request.*;
|
||||
|
||||
/**
|
||||
* JustAuth内置的各api需要的url, 用枚举类分平台类型管理
|
||||
@@ -28,6 +29,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String userInfo() {
|
||||
return "https://api.github.com/user";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthGithubRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 新浪微博
|
||||
@@ -52,6 +58,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String revoke() {
|
||||
return "https://api.weibo.com/oauth2/revokeoauth2";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthWeiboRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* gitee
|
||||
@@ -71,9 +82,14 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String userInfo() {
|
||||
return "https://gitee.com/api/v5/user";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthGiteeRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 钉钉
|
||||
* 钉钉扫码登录
|
||||
*/
|
||||
DINGTALK {
|
||||
@Override
|
||||
@@ -90,6 +106,35 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String userInfo() {
|
||||
return "https://oapi.dingtalk.com/sns/getuserinfo_bycode";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthDingTalkRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 钉钉账号登录
|
||||
*/
|
||||
DINGTALK_ACCOUNT {
|
||||
@Override
|
||||
public String authorize() {
|
||||
return "https://oapi.dingtalk.com/connect/oauth2/sns_authorize";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String accessToken() {
|
||||
return DINGTALK.accessToken();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String userInfo() {
|
||||
return DINGTALK.userInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthDingTalkAccountRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 百度
|
||||
@@ -119,6 +164,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String refresh() {
|
||||
return "https://openapi.baidu.com/oauth/2.0/token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthBaiduRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* csdn
|
||||
@@ -138,10 +188,15 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String userInfo() {
|
||||
return "https://api.csdn.net/user/getinfo";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthCsdnRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Coding,
|
||||
*
|
||||
* <p>
|
||||
* 参考 https://help.coding.net/docs/project/open/oauth.html#%E7%94%A8%E6%88%B7%E6%8E%88%E6%9D%83 中的说明,
|
||||
* 新版的 coding API 地址需要传入用户团队名,这儿使用动态参数,方便在 request 中使用
|
||||
*/
|
||||
@@ -160,6 +215,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String userInfo() {
|
||||
return "https://%s.coding.net/api/account/current_user";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthCodingRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* oschina 开源中国
|
||||
@@ -179,6 +239,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String userInfo() {
|
||||
return "https://www.oschina.net/action/openapi/user";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthOschinaRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 支付宝
|
||||
@@ -198,6 +263,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String userInfo() {
|
||||
return "https://openapi.alipay.com/gateway.do";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthAlipayRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* QQ
|
||||
@@ -222,6 +292,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String refresh() {
|
||||
return "https://graph.qq.com/oauth2.0/token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthQqRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 微信开放平台
|
||||
@@ -246,6 +321,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String refresh() {
|
||||
return "https://api.weixin.qq.com/sns/oauth2/refresh_token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthWeChatOpenRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 微信公众平台
|
||||
@@ -270,6 +350,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String refresh() {
|
||||
return "https://api.weixin.qq.com/sns/oauth2/refresh_token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthWeChatMpRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 淘宝
|
||||
@@ -289,6 +374,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String userInfo() {
|
||||
throw new AuthException(AuthResponseStatus.UNSUPPORTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthTaobaoRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Google
|
||||
@@ -308,6 +398,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String userInfo() {
|
||||
return "https://www.googleapis.com/oauth2/v3/userinfo";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthGoogleRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Facebook
|
||||
@@ -315,17 +410,22 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
FACEBOOK {
|
||||
@Override
|
||||
public String authorize() {
|
||||
return "https://www.facebook.com/v3.3/dialog/oauth";
|
||||
return "https://www.facebook.com/v10.0/dialog/oauth";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String accessToken() {
|
||||
return "https://graph.facebook.com/v3.3/oauth/access_token";
|
||||
return "https://graph.facebook.com/v10.0/oauth/access_token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String userInfo() {
|
||||
return "https://graph.facebook.com/v3.3/me";
|
||||
return "https://graph.facebook.com/v10.0/me";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthFacebookRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -351,6 +451,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String refresh() {
|
||||
return "https://open.douyin.com/oauth/refresh_token/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthDouyinRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 领英
|
||||
@@ -375,6 +480,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String refresh() {
|
||||
return "https://www.linkedin.com/oauth/v2/accessToken";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthLinkedinRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 微软
|
||||
@@ -399,6 +509,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String refresh() {
|
||||
return "https://login.microsoftonline.com/common/oauth2/v2.0/token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthMicrosoftRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 小米
|
||||
@@ -423,6 +538,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String refresh() {
|
||||
return "https://account.xiaomi.com/oauth2/token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthMiRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 今日头条
|
||||
@@ -442,6 +562,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String userInfo() {
|
||||
return "https://open.snssdk.com/data/user_profile";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthToutiaoRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Teambition
|
||||
@@ -466,6 +591,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String userInfo() {
|
||||
return "https://api.teambition.com/users/me";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthTeambitionRequest.class;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -491,6 +621,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String userInfo() {
|
||||
return "https://api.renren.com/v2/user/get";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthRenrenRequest.class;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -511,6 +646,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String userInfo() {
|
||||
return "https://api.pinterest.com/v1/me";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthPinterestRequest.class;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -531,6 +671,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String userInfo() {
|
||||
return "https://api.stackexchange.com/2.2/me";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthStackOverflowRequest.class;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -558,10 +703,15 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String refresh() {
|
||||
return "https://oauth-login.cloud.huawei.com/oauth2/v2/token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthHuaweiRequest.class;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 企业微信
|
||||
* 企业微信二维码登录
|
||||
*
|
||||
* @since 1.10.0
|
||||
*/
|
||||
@@ -580,6 +730,74 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String userInfo() {
|
||||
return "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthWeChatEnterpriseQrcodeRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 企业微信二维码第三方登录
|
||||
*/
|
||||
WECHAT_ENTERPRISE_QRCODE_THIRD {
|
||||
/**
|
||||
* 授权的api
|
||||
*
|
||||
* @return url
|
||||
*/
|
||||
@Override
|
||||
public String authorize() {
|
||||
return "https://open.work.weixin.qq.com/wwopen/sso/3rd_qrConnect";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取accessToken的api
|
||||
*
|
||||
* @return url
|
||||
*/
|
||||
@Override
|
||||
public String accessToken() {
|
||||
return "https://qyapi.weixin.qq.com/cgi-bin/service/get_provider_token";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息的api
|
||||
*
|
||||
* @return url
|
||||
*/
|
||||
@Override
|
||||
public String userInfo() {
|
||||
return "https://qyapi.weixin.qq.com/cgi-bin/service/get_login_info";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthWeChatEnterpriseThirdQrcodeRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 企业微信网页登录
|
||||
*/
|
||||
WECHAT_ENTERPRISE_WEB {
|
||||
@Override
|
||||
public String authorize() {
|
||||
return "https://open.weixin.qq.com/connect/oauth2/authorize";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String accessToken() {
|
||||
return "https://qyapi.weixin.qq.com/cgi-bin/gettoken";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String userInfo() {
|
||||
return "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthWeChatEnterpriseWebRequest.class;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -607,6 +825,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String refresh() {
|
||||
return "https://oauth.kujiale.com/oauth2/auth/token/refresh";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthKujialeRequest.class;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -629,6 +852,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String userInfo() {
|
||||
return "https://gitlab.com/api/v4/user";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthGitlabRequest.class;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -656,6 +884,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String refresh() {
|
||||
return "https://openapi.waimai.meituan.com/oauth/refresh_token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthMeituanRequest.class;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -685,6 +918,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String refresh() {
|
||||
return "https://open-api.shop.ele.me/token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthElemeRequest.class;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -705,35 +943,46 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
|
||||
@Override
|
||||
public String userInfo() {
|
||||
return "https://api.twitter.com/1.1/users/show.json";
|
||||
return "https://api.twitter.com/1.1/account/verify_credentials.json";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthTwitterRequest.class;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 飞书
|
||||
* 注意:该平台暂时存在问题,请不要使用。待修复完成后会重新发版
|
||||
* 飞书平台,企业自建应用授权登录,原逻辑由 beacon 集成于 1.14.0 版,但最新的飞书 api 已修改,并且飞书平台一直为 {@code Deprecated} 状态
|
||||
* <p>
|
||||
* 所以,最终修改该平台的实际发布版本为 1.15.9
|
||||
*
|
||||
* @since 1.14.0
|
||||
* @since 1.15.9
|
||||
*/
|
||||
FEISHU {
|
||||
@Override
|
||||
public String authorize() {
|
||||
return "https://open.feishu.cn/connect/qrconnect/page/sso/";
|
||||
return "https://open.feishu.cn/open-apis/authen/v1/index";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String accessToken() {
|
||||
return "https://open.feishu.cn/connect/qrconnect/oauth2/access_token/";
|
||||
return "https://open.feishu.cn/open-apis/authen/v1/access_token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String userInfo() {
|
||||
return "https://open.feishu.cn/connect/qrconnect/oauth2/user_info/";
|
||||
return "https://open.feishu.cn/open-apis/authen/v1/user_info";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String refresh() {
|
||||
return "https://open.feishu.cn/connect/qrconnect/oauth2/access_token/";
|
||||
return "https://open.feishu.cn/open-apis/authen/v1/refresh_access_token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthFeishuRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -761,6 +1010,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String refresh() {
|
||||
return "https://open-oauth.jd.com/oauth2/refresh_token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthJdRequest.class;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -786,6 +1040,211 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String refresh() {
|
||||
return "https://oauth.aliyun.com/v1/token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthAliyunRequest.class;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 喜马拉雅
|
||||
*/
|
||||
XMLY {
|
||||
@Override
|
||||
public String authorize() {
|
||||
return "https://api.ximalaya.com/oauth2/js/authorize";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String accessToken() {
|
||||
return "https://api.ximalaya.com/oauth2/v2/access_token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String userInfo() {
|
||||
return "https://api.ximalaya.com/profile/user_info";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String refresh() {
|
||||
return "https://oauth.aliyun.com/v1/token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthXmlyRequest.class;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Amazon
|
||||
*
|
||||
* @since 1.16.0
|
||||
*/
|
||||
AMAZON {
|
||||
@Override
|
||||
public String authorize() {
|
||||
return "https://www.amazon.com/ap/oa";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String accessToken() {
|
||||
return "https://api.amazon.com/auth/o2/token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String userInfo() {
|
||||
return "https://api.amazon.com/user/profile";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String refresh() {
|
||||
return "https://api.amazon.com/auth/o2/token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthAmazonRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Slack
|
||||
*
|
||||
* @since 1.16.0
|
||||
*/
|
||||
SLACK {
|
||||
@Override
|
||||
public String authorize() {
|
||||
return "https://slack.com/oauth/v2/authorize";
|
||||
}
|
||||
|
||||
/**
|
||||
* 该 API 获取到的是 access token
|
||||
*
|
||||
* https://slack.com/api/oauth.token 获取到的是 workspace token
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
@Override
|
||||
public String accessToken() {
|
||||
return "https://slack.com/api/oauth.v2.access";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String userInfo() {
|
||||
return "https://slack.com/api/users.info";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String revoke() {
|
||||
return "https://slack.com/api/auth.revoke";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthSlackRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* line
|
||||
*
|
||||
* @since 1.16.0
|
||||
*/
|
||||
LINE {
|
||||
@Override
|
||||
public String authorize() {
|
||||
return "https://access.line.me/oauth2/v2.1/authorize";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String accessToken() {
|
||||
return "https://api.line.me/oauth2/v2.1/token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String userInfo() {
|
||||
return "https://api.line.me/v2/profile";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String refresh() {
|
||||
return "https://api.line.me/oauth2/v2.1/token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String revoke() {
|
||||
return "https://api.line.me/oauth2/v2.1/revoke";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthLineRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Okta,
|
||||
* <p>
|
||||
* 团队/组织的域名不同,此处通过配置动态组装
|
||||
*
|
||||
* @since 1.16.0
|
||||
*/
|
||||
OKTA {
|
||||
@Override
|
||||
public String authorize() {
|
||||
return "https://%s.okta.com/oauth2/%s/v1/authorize";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String accessToken() {
|
||||
return "https://%s.okta.com/oauth2/%s/v1/token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String refresh() {
|
||||
return "https://%s.okta.com/oauth2/%s/v1/token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String userInfo() {
|
||||
return "https://%s.okta.com/oauth2/%s/v1/userinfo";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String revoke() {
|
||||
return "https://%s.okta.com/oauth2/%s/v1/revoke";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthOktaRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 程序员客栈
|
||||
*
|
||||
* @since 1.16.2
|
||||
*/
|
||||
PROGINN {
|
||||
@Override
|
||||
public String authorize() {
|
||||
return "https://www.proginn.com/oauth2/authorize";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String accessToken() {
|
||||
return "https://www.proginn.com/oauth2/access_token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String userInfo() {
|
||||
return "https://www.proginn.com/openapi/user/basic_info";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthProginnRequest.class;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package me.zhyd.oauth.config;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.request.AuthDefaultRequest;
|
||||
|
||||
/**
|
||||
* OAuth平台的API地址的统一接口,提供以下方法:
|
||||
@@ -73,4 +74,11 @@ public interface AuthSource {
|
||||
}
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 平台对应的 AuthRequest 实现类,必须继承自 {@link AuthDefaultRequest}
|
||||
*
|
||||
* @return class
|
||||
*/
|
||||
Class<? extends AuthDefaultRequest> getTargetClass();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package me.zhyd.oauth.config;
|
||||
|
||||
import me.zhyd.oauth.log.Log;
|
||||
|
||||
/**
|
||||
* JustAuth 日志配置类
|
||||
*
|
||||
* @author HeJin
|
||||
*/
|
||||
public class JustAuthLogConfig {
|
||||
|
||||
/**
|
||||
* 设置日志级别
|
||||
*
|
||||
* @param level 日志级别
|
||||
*/
|
||||
public static void setLevel(Log.Level level) {
|
||||
Log.Config.level = level;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭日志
|
||||
*/
|
||||
public static void disable() {
|
||||
Log.Config.enable = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启日志
|
||||
*/
|
||||
public static void enable() {
|
||||
Log.Config.enable = true;
|
||||
}
|
||||
}
|
||||
@@ -28,9 +28,10 @@ public enum AuthResponseStatus {
|
||||
ILLEGAL_CODE(5008, "Illegal code"),
|
||||
ILLEGAL_STATUS(5009, "Illegal state"),
|
||||
REQUIRED_REFRESH_TOKEN(5010, "The refresh token is required; it must not be null"),
|
||||
ILLEGAL_TOKEN(5011, "Invalid token"),
|
||||
;
|
||||
|
||||
private int code;
|
||||
private String msg;
|
||||
private final int code;
|
||||
private final String msg;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package me.zhyd.oauth.enums.scope;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Amazon平台 OAuth 授权范围
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.16.0
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum AuthAmazonScope implements AuthScope {
|
||||
|
||||
/**
|
||||
* {@code scope} 含义,以{@code description} 为准
|
||||
*/
|
||||
R_LITEPROFILE("profile", "The profile scope includes a user's name and email address", true),
|
||||
R_EMAILADDRESS("profile:user_id", "The profile:user_id scope only includes the user_id field of the profile", true),
|
||||
W_MEMBER_SOCIAL("postal_code", "This includes the user's zip/postal code number from their primary shipping address", true);
|
||||
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 边度平台 OAuth 授权范围
|
||||
* 百度平台 OAuth 授权范围
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
@@ -23,8 +23,8 @@ public enum AuthBaiduScope implements AuthScope {
|
||||
PUBLIC("public", "可以访问公共的开放API。", false),
|
||||
HAO123("hao123", "可以访问Hao123 提供的开放API接口。该权限需要申请开通,请将具体的理由和用途发邮件给tuangou@baidu.com。", false);
|
||||
|
||||
private String scope;
|
||||
private String description;
|
||||
private boolean isDefault;
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ public enum AuthCodingScope implements AuthScope {
|
||||
PROJECT_DEPOT("project:depot", "完整的仓库控制权限", false),
|
||||
PROJECT_WIKI("project:wiki", "授权读取与操作 wiki", false),
|
||||
;
|
||||
private String scope;
|
||||
private String description;
|
||||
private boolean isDefault;
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package me.zhyd.oauth.enums.scope;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 抖音平台 OAuth 授权范围
|
||||
*
|
||||
* https://open.douyin.com/platform/doc/6855240178122983437
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.16.1
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum AuthDouyinScope implements AuthScope {
|
||||
|
||||
/**
|
||||
* 无需申请 默认开启
|
||||
*/
|
||||
USER_INFO("user_info", "返回抖音用户公开信息", true),
|
||||
/**
|
||||
* 无需申请 默认开启
|
||||
*/
|
||||
AWEME_SHARE("aweme.share", "抖音分享", false),
|
||||
/**
|
||||
* 普通权限,管理中心申请
|
||||
*/
|
||||
IM_SHARE("im.share", "分享给抖音好友", false),
|
||||
RENEW_REFRESH_TOKEN("renew_refresh_token", "授权有效期动态续期", false),
|
||||
FOLLOWING_LIST("following.list", "获取该用户的关注列表", false),
|
||||
FANS_LIST("fans.list", "获取该用户的粉丝列表", false),
|
||||
VIDEO_CREATE("video.create", "视频发布及管理", false),
|
||||
VIDEO_DELETE("video.delete", "删除内容", false),
|
||||
VIDEO_DATA("video.data", "查询授权用户的抖音视频数据", false),
|
||||
VIDEO_LIST("video.list", "查询特定抖音视频的视频数据", false),
|
||||
/**
|
||||
* 特殊权限 默认关闭 管理中心申请
|
||||
*/
|
||||
SHARE_WITH_SOURCE("share_with_source", "分享携带来源标签,用户可点击标签进入转化页", false),
|
||||
MOBILE("mobile", "用抖音帐号登录第三方平台,获得用户在抖音上的手机号码", false),
|
||||
MOBILE_ALERT("mobile_alert", "用抖音帐号登录第三方平台,获得用户在抖音上的手机号码", false),
|
||||
VIDEO_SEARCH("video.search", "关键词视频管理", false),
|
||||
POI_SEARCH("poi.search", "查询POI信息", false),
|
||||
LOGIN_ID("login_id", "静默授权直接获取该用户的open id", false),
|
||||
/**
|
||||
* 抖音数据权限, 默认关闭, 管理中心申请
|
||||
*/
|
||||
DATA_EXTERNAL_USER("data.external.user", "查询用户的获赞、评论、分享,主页访问等相关数据", false),
|
||||
DATA_EXTERNAL_ITEM("data.external.item", "查询作品的获赞,评论,分享等相关数据", false),
|
||||
FANS_DATA("fans.data", "获取用户粉丝画像数据", false),
|
||||
HOTSEARCH("hotsearch", "获取抖音热门内容", false),
|
||||
STAR_TOP_SCORE_DISPLAY("star_top_score_display", "星图达人与达人对应各指数评估分,以及星图6大热门维度下的达人榜单", false),
|
||||
STAR_TOPS("star_tops", "星图达人与达人对应各指数评估分,以及星图6大热门维度下的达人榜单", false),
|
||||
STAR_AUTHOR_SCORE_DISPLAY("star_author_score_display", "星图达人与达人对应各指数评估分,以及星图6大热门维度下的达人榜单", false),
|
||||
notes("data.external.sdk_share", "获取用户通过分享SDK分享视频数据", false),
|
||||
/**
|
||||
* 定向开通 默认关闭 定向开通
|
||||
*/
|
||||
DISCOVERY_ENT("discovery.ent", "查询抖音电影榜、抖音剧集榜、抖音综艺榜数据", false),
|
||||
;
|
||||
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
@@ -17,24 +17,24 @@ public enum AuthFacebookScope implements AuthScope {
|
||||
/**
|
||||
* {@code scope} 含义,以{@code description} 为准
|
||||
*/
|
||||
EMAIL("email", "获取用户的邮箱", false),
|
||||
USER_AGE_RANGE("user_age_range", "允许应用程序访问用户的年龄范围", false),
|
||||
USER_BIRTHDAY("user_birthday", "获取用户的生日", false),
|
||||
USER_FRIENDS("user_friends", "获取用户的好友列表", false),
|
||||
USER_GENDER("user_gender", "获取用户的性别", false),
|
||||
USER_HOMETOWN("user_hometown", "获取用户的家乡信息", false),
|
||||
USER_LIKES("user_likes", "获取用户的喜欢列表", false),
|
||||
USER_LINK("user_link", "获取用户的个人链接", false),
|
||||
USER_LOCATION("user_location", "获取用户的位置信息", false),
|
||||
USER_PHOTOS("user_photos", "获取用户的相册信息", false),
|
||||
USER_POSTS("user_posts", "获取用户发布的内容", false),
|
||||
USER_VIDEOS("user_videos", "获取用户上传的视频信息", false),
|
||||
EMAIL("email", "获取用户的邮箱", true),
|
||||
USER_AGE_RANGE("user_age_range", "允许应用程序访问用户的年龄范围", true),
|
||||
USER_BIRTHDAY("user_birthday", "获取用户的生日", true),
|
||||
USER_FRIENDS("user_friends", "获取用户的好友列表", true),
|
||||
USER_GENDER("user_gender", "获取用户的性别", true),
|
||||
USER_HOMETOWN("user_hometown", "获取用户的家乡信息", true),
|
||||
USER_LIKES("user_likes", "获取用户的喜欢列表", true),
|
||||
USER_LINK("user_link", "获取用户的个人链接", true),
|
||||
USER_LOCATION("user_location", "获取用户的位置信息", true),
|
||||
USER_PHOTOS("user_photos", "获取用户的相册信息", true),
|
||||
USER_POSTS("user_posts", "获取用户发布的内容", true),
|
||||
USER_VIDEOS("user_videos", "获取用户上传的视频信息", true),
|
||||
GROUPS_ACCESS_MEMBER_INFO("groups_access_member_info", "获取公开的群组成员信息", false),
|
||||
PUBLISH_TO_GROUPS("publish_to_groups", "授权您的应用程序代表某人将内容发布到组中,前提是他们已经授予您的应用程序访问权限", false),
|
||||
;
|
||||
|
||||
private String scope;
|
||||
private String description;
|
||||
private boolean isDefault;
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ public enum AuthGiteeScope implements AuthScope {
|
||||
ENTERPRISES("enterprises", "查看、管理用户的企业以及成员", false),
|
||||
EMAILS("emails", "查看用户的个人邮箱信息", false);
|
||||
|
||||
private String scope;
|
||||
private String description;
|
||||
private boolean isDefault;
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 边度平台 OAuth 授权范围
|
||||
* Github平台 OAuth 授权范围
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
@@ -47,8 +47,8 @@ public enum AuthGithubScope implements AuthScope {
|
||||
READ_GPG_KEY("read:gpg_key", "List and view details for GPG keys.", false),
|
||||
WORKFLOW("workflow", "Grants the ability to add and update GitHub Actions workflow files. Workflow files can be committed without this scope if the same file (with both the same path and contents) exists on another branch in the same repository.", false),
|
||||
;
|
||||
private String scope;
|
||||
private String description;
|
||||
private boolean isDefault;
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ public enum AuthGitlabScope implements AuthScope {
|
||||
API("api", "Grants complete read/write access to the API, including all groups and projects, the container registry, and the package registry.", false),
|
||||
;
|
||||
|
||||
private String scope;
|
||||
private String description;
|
||||
private boolean isDefault;
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
|
||||
@@ -281,9 +281,9 @@ public enum AuthGoogleScope implements AuthScope {
|
||||
ADEXCHANGE_BUYER("https://www.googleapis.com/auth/adexchange.buyer", "Manage your Ad Exchange buyer account configuration", false),
|
||||
;
|
||||
|
||||
private String scope;
|
||||
private String description;
|
||||
private boolean isDefault;
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
|
||||
public static List<String> getAdminDirectoryScopes() {
|
||||
|
||||
@@ -39,8 +39,8 @@ public enum AuthHuaweiScope implements AuthScope {
|
||||
|
||||
;
|
||||
|
||||
private String scope;
|
||||
private String description;
|
||||
private boolean isDefault;
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ public enum AuthJdScope implements AuthScope {
|
||||
*/
|
||||
SNSAPI_BASE("snsapi_base", "基础授权", true);
|
||||
|
||||
private String scope;
|
||||
private String description;
|
||||
private boolean isDefault;
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ public enum AuthKujialeScope implements AuthScope {
|
||||
GET_DESIGN("get_design", "获取指定方案详情", false),
|
||||
GET_BUDGET_LIST("get_budget_list", "获取清单预算概览数据", false);
|
||||
|
||||
private String scope;
|
||||
private String description;
|
||||
private boolean isDefault;
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package me.zhyd.oauth.enums.scope;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Line 平台 OAuth 授权范围
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.16.0
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum AuthLineScope implements AuthScope {
|
||||
|
||||
/**
|
||||
* {@code scope} 含义,以{@code description} 为准
|
||||
*/
|
||||
|
||||
PROFILE("profile", "Get profile details", true),
|
||||
OPENID("openid", "Get id token", true),
|
||||
EMAIL("email", "Get email (separate authorization required)", false);
|
||||
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
@@ -36,8 +36,8 @@ public enum AuthLinkedinScope implements AuthScope {
|
||||
W_ORGANIZATION_SOCIAL("w_organization_social", "Post, comment and like posts on your organization's behalf", false),
|
||||
W_SHARE("w_share", "Post updates to LinkedIn as you", false);
|
||||
|
||||
private String scope;
|
||||
private String description;
|
||||
private boolean isDefault;
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ public enum AuthMiScope implements AuthScope {
|
||||
OPENID("user/openIdV2", "获取用户的OpenID", true),
|
||||
PHONE_EMAIL("user/phoneAndEmail", "获取用户的手机号和邮箱", true);
|
||||
|
||||
private String scope;
|
||||
private String description;
|
||||
private boolean isDefault;
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
|
||||
@@ -60,8 +60,8 @@ public enum AuthMicrosoftScope implements AuthScope {
|
||||
NOTES_READWRITE_ALL("Notes.ReadWrite.All", "允许应用读取、共享和修改已登录用户在组织中有权访问的 OneNote 笔记本", false),
|
||||
;
|
||||
|
||||
private String scope;
|
||||
private String description;
|
||||
private boolean isDefault;
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package me.zhyd.oauth.enums.scope;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Okta 平台 OAuth 授权范围
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.16.0
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum AuthOktaScope implements AuthScope {
|
||||
|
||||
/**
|
||||
* {@code scope} 含义,以{@code description} 为准
|
||||
*/
|
||||
OPENID("openid", "Signals that a request is an OpenID request.", true),
|
||||
PROFILE("profile", "The exact data varies based on what profile information you have provided, such as: name, time zone, picture, or birthday.", true),
|
||||
EMAIL("email", "This allows the app to view your email address.", true),
|
||||
ADDRESS("address", "This allows the app to view your address, such as: street address, city, state, and zip code.", true),
|
||||
PHONE("phone", "This allows the app to view your phone number.", true),
|
||||
OFFLINE_ACCESS("offline_access", "This keeps you signed in to the app, even when you are not using it.", true),
|
||||
OKTA_USERS_MANAGE("okta.users.manage", "Allows the app to create and manage users and read all profile and credential information for users", false),
|
||||
OKTA_USERS_READ("okta.users.read", "Allows the app to read any user's profile and credential information", false),
|
||||
OKTA_USERS_MANAGE_SELF("okta.users.manage.self", "Allows the app to manage the currently signed-in user's profile. Currently only supports user profile attribute updates.", false),
|
||||
OKTA_USERS_READ_SELF("okta.users.read.self", "Allows the app to read the currently signed-in user's profile and credential information", false),
|
||||
OKTA_APPS_MANAGE("okta.apps.manage", "Allows the app to create and manage Apps in your Okta organization", false),
|
||||
OKTA_APPS_READ("okta.apps.read", "Allows the app to read information about Apps in your Okta organization", false),
|
||||
OKTA_AUTHORIZATIONSERVERS_MANAGE("okta.authorizationServers.manage", "Allows the app to manage authorization servers", false),
|
||||
OKTA_AUTHORIZATIONSERVERS_READ("okta.authorizationServers.read", "Allows the app to read authorization server information", false),
|
||||
OKTA_CLIENTS_MANAGE("okta.clients.manage", "Allows the app to manage all OAuth/OIDC clients and to create new clients", false),
|
||||
OKTA_CLIENTS_READ("okta.clients.read", "Allows the app to read information for all OAuth/OIDC clients", false),
|
||||
OKTA_CLIENTS_REGISTER("okta.clients.register", "Allows the app to register (create) new OAuth/OIDC clients (but not read information about existing clients)", false),
|
||||
OKTA_EVENTHOOKS_MANAGE("okta.eventHooks.manage", "Allows the app to create and manage Event Hooks in your Okta organization", false),
|
||||
OKTA_EVENTHOOKS_READ("okta.eventHooks.read", "Allows the app to read information about Event Hooks in your Okta organization", false),
|
||||
OKTA_FACTORS_MANAGE("okta.factors.manage", "Allows the app to manage all admin operations for org factors (for example, activate, deactive, read)", false),
|
||||
OKTA_FACTORS_READ("okta.factors.read", "Allows the app to read org factors information", false),
|
||||
OKTA_GROUPS_MANAGE("okta.groups.manage", "Allows the app to manage groups in your Okta organization", false),
|
||||
OKTA_GROUPS_READ("okta.groups.read", "Allows the app to read information about groups and their members in your Okta organization", false),
|
||||
OKTA_IDPS_MANAGE("okta.idps.manage", "Allows the app to create and manage Identity Providers in your Okta organization", false),
|
||||
OKTA_IDPS_READ("okta.idps.read", "Allows the app to read information about Identity Providers in your Okta organization", false),
|
||||
OKTA_INLINEHOOKS_MANAGE("okta.inlineHooks.manage", "Allows the app to create and manage Inline Hooks in your Okta organization.", false),
|
||||
OKTA_INLINEHOOKS_READ("okta.inlineHooks.read", "Allows the app to read information about Inline Hooks in your Okta organization.", false),
|
||||
OKTA_LINKEDOBJECTS_MANAGE("okta.linkedObjects.manage", "Allows the app to manage Linked Object definitions in your Okta organization.", false),
|
||||
OKTA_LINKEDOBJECTS_READ("okta.linkedObjects.read", "Allows the app to read Linked Object definitions in your Okta organization.", false),
|
||||
OKTA_LOGS_READ("okta.logs.read", "Allows the app to read information about System Log entries in your Okta organization", false),
|
||||
OKTA_ROLES_MANAGE("okta.roles.manage", "Allows the app to create and manage Administrator Roles in your Okta organization", false),
|
||||
OKTA_ROLES_READ("okta.roles.read", "Allows the app to read information about Administrator Roles in your Okta organization", false),
|
||||
OKTA_SCHEMAS_MANAGE("okta.schemas.manage", "Allows the app to create and manage Schemas in your Okta organization", false),
|
||||
OKTA_SCHEMAS_READ("okta.schemas.read", "Allows the app to read information about Schemas in your Okta organization", false),
|
||||
OKTA_SESSIONS_MANAGE("okta.sessions.manage", "Allows the app to manage all sessions in your Okta organization", false),
|
||||
OKTA_SESSIONS_READ("okta.sessions.read", "Allows the app to read all sessions in your Okta organization", false),
|
||||
OKTA_TEMPLATES_MANAGE("okta.templates.manage", "Allows the app to manage all custom templates in your Okta organization", false),
|
||||
OKTA_TEMPLATES_READ("okta.templates.read", "Allows the app to read all custom templates in your Okta organization", false),
|
||||
OKTA_TRUSTEDORIGINS_MANAGE("okta.trustedOrigins.manage", "Allows the app to manage all Trusted Origins in your Okta organization", false),
|
||||
OKTA_TRUSTEDORIGINS_READ("okta.trustedOrigins.read", "Allows the app to read all Trusted Origins in your Okta organization", false),
|
||||
OKTA_POLICIES_MANAGE("okta.policies.manage", "Allows the app to manage Policies in your Okta organization", false),
|
||||
OKTA_POLICIES_READ("okta.policies.read", "Allows the app to read information about Policies in your Okta organization", false),;
|
||||
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
@@ -23,8 +23,8 @@ public enum AuthPinterestScope implements AuthScope {
|
||||
WRITE_RELATIONSHIPS("write_relationships", "Use PATCH, POST and DELETE methods on a user’s follows and followers (on boards, users and interests).", false),
|
||||
;
|
||||
|
||||
private String scope;
|
||||
private String description;
|
||||
private boolean isDefault;
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package me.zhyd.oauth.enums.scope;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Gitee 平台 OAuth 授权范围
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum AuthProginnScope implements AuthScope {
|
||||
|
||||
/**
|
||||
* {@code scope} 含义,以{@code description} 为准
|
||||
*/
|
||||
BASIC("basic", "访问用户的基本信息", true),
|
||||
/**
|
||||
* 以上 scope 需要单独向程序员客栈平台申请,否则不可使用
|
||||
*/
|
||||
email("email", "获取用户的邮箱", false),
|
||||
realname("realname", "获取用户的真实姓名", false),
|
||||
cellphone("cellphone", "获取用户的手机号码", false),
|
||||
;
|
||||
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
@@ -28,8 +28,8 @@ public enum AuthQqScope implements AuthScope {
|
||||
ADD_ALBUM("add_album", "在用户的空间相册里,创建一个新的个人相册", false),
|
||||
LIST_PHOTO("list_photo", "获取用户QQ空间相册中的照片列表", false);
|
||||
|
||||
private String scope;
|
||||
private String description;
|
||||
private boolean isDefault;
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
|
||||
@@ -48,8 +48,8 @@ public enum AuthRenrenScope implements AuthScope {
|
||||
ADMIN_PAGE("admin_page", "以用户的身份,管理其可以管理的公共主页的权限。", false),
|
||||
;
|
||||
|
||||
private String scope;
|
||||
private String description;
|
||||
private boolean isDefault;
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
package me.zhyd.oauth.enums.scope;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Slack 平台 OAuth 授权范围
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.16.0
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum AuthSlackScope implements AuthScope {
|
||||
|
||||
/**
|
||||
* {@code scope} 含义,以{@code description} 为准
|
||||
*/
|
||||
USERS_PROFILE_READ("users.profile:read", "View profile details about people in a workspace", true),
|
||||
USERS_READ("users:read", "View people in a workspace", true),
|
||||
USERS_READ_EMAIL("users:read.email", "View email addresses of people in a workspace", true),
|
||||
USERS_PROFILE_WRITE("users.profile:write", "Edit a user’s profile information and status", false),
|
||||
USERS_PROFILE_WRITE_USER("users.profile:write:user", "Change the user's profile fields", false),
|
||||
USERS_WRITE("users:write", "Set presence for your slack app", false),
|
||||
ADMIN("admin", "Administer a workspace", false),
|
||||
ADMIN_ANALYTICS_READ("admin.analytics:read", "Access analytics data about the organization", false),
|
||||
ADMIN_APPS_READ("admin.apps:read", "View apps and app requests in a workspace", false),
|
||||
ADMIN_APPS_WRITE("admin.apps:write", "Manage apps in a workspace", false),
|
||||
ADMIN_BARRIERS_READ("admin.barriers:read", "Read information barriers in the organization", false),
|
||||
ADMIN_BARRIERS_WRITE("admin.barriers:write", "Manage information barriers in the organization", false),
|
||||
ADMIN_CONVERSATIONS_READ("admin.conversations:read", "View the channel’s member list, topic, purpose and channel name", false),
|
||||
ADMIN_CONVERSATIONS_WRITE("admin.conversations:write", "Start a new conversation, modify a conversation and modify channel details", false),
|
||||
ADMIN_INVITES_READ("admin.invites:read", "Gain information about invite requests in a Grid organization.", false),
|
||||
ADMIN_INVITES_WRITE("admin.invites:write", "Approve or deny invite requests in a Grid organization.", false),
|
||||
ADMIN_TEAMS_READ("admin.teams:read", "Access information about a workspace", false),
|
||||
ADMIN_TEAMS_WRITE("admin.teams:write", "Make changes to a workspace", false),
|
||||
ADMIN_USERGROUPS_READ("admin.usergroups:read", "Access information about user groups", false),
|
||||
ADMIN_USERGROUPS_WRITE("admin.usergroups:write", "Make changes to your usergroups", false),
|
||||
ADMIN_USERS_READ("admin.users:read", "Access a workspace’s profile information", false),
|
||||
ADMIN_USERS_WRITE("admin.users:write", "Modify account information", false),
|
||||
APP_MENTIONS_READ("app_mentions:read", "View messages that directly mention @your_slack_app in conversations that the app is in", false),
|
||||
AUDITLOGS_READ("auditlogs:read", "View events from all workspaces, channels and users (Enterprise Grid only)", false),
|
||||
BOT("bot", "Add the ability for people to direct message or mention @your_slack_app", false),
|
||||
CALLS_READ("calls:read", "View information about ongoing and past calls", false),
|
||||
CALLS_WRITE("calls:write", "Start and manage calls in a workspace", false),
|
||||
CHANNELS_HISTORY("channels:history", "View messages and other content in public channels that your slack app has been added to", false),
|
||||
CHANNELS_JOIN("channels:join", "Join public channels in a workspace", false),
|
||||
CHANNELS_MANAGE("channels:manage", "Manage public channels that your slack app has been added to and create new ones", false),
|
||||
CHANNELS_READ("channels:read", "View basic information about public channels in a workspace", false),
|
||||
CHANNELS_WRITE("channels:write", "Manage a user’s public channels and create new ones on a user’s behalf", false),
|
||||
CHAT_WRITE("chat:write", "Post messages in approved channels & conversations", false),
|
||||
CHAT_WRITE_CUSTOMIZE("chat:write.customize", "Send messages as @your_slack_app with a customized username and avatar", false),
|
||||
CHAT_WRITE_PUBLIC("chat:write.public", "Send messages to channels @your_slack_app isn't a member of", false),
|
||||
CHAT_WRITE_BOT("chat:write:bot", "Send messages as your slack app", false),
|
||||
CHAT_WRITE_USER("chat:write:user", "Send messages on a user’s behalf", false),
|
||||
CLIENT("client", "Receive all events from a workspace in real time", false),
|
||||
COMMANDS("commands", "Add shortcuts and/or slash commands that people can use", false),
|
||||
CONVERSATIONS_HISTORY("conversations:history", "Deprecated: Retrieve conversation history for legacy workspace apps", false),
|
||||
CONVERSATIONS_READ("conversations:read", "Deprecated: Retrieve information on conversations for legacy workspace apps", false),
|
||||
CONVERSATIONS_WRITE("conversations:write", "Deprecated: Edit conversation attributes for legacy workspace apps", false),
|
||||
DND_READ("dnd:read", "View Do Not Disturb settings for people in a workspace", false),
|
||||
DND_WRITE("dnd:write", "Edit a user’s Do Not Disturb settings", false),
|
||||
DND_WRITE_USER("dnd:write:user", "Change the user's Do Not Disturb settings", false),
|
||||
EMOJI_READ("emoji:read", "View custom emoji in a workspace", false),
|
||||
FILES_READ("files:read", "View files shared in channels and conversations that your slack app has been added to", false),
|
||||
FILES_WRITE("files:write", "Upload, edit, and delete files as your slack app", false),
|
||||
FILES_WRITE_USER("files:write:user", "Upload, edit, and delete files as your slack app", false),
|
||||
GROUPS_HISTORY("groups:history", "View messages and other content in private channels that your slack app has been added to", false),
|
||||
GROUPS_READ("groups:read", "View basic information about private channels that your slack app has been added to", false),
|
||||
GROUPS_WRITE("groups:write", "Manage private channels that your slack app has been added to and create new ones", false),
|
||||
IDENTIFY("identify", "View information about a user’s identity", false),
|
||||
IDENTITY_AVATAR("identity.avatar", "View a user’s Slack avatar", false),
|
||||
IDENTITY_AVATAR_READ_USER("identity.avatar:read:user", "View the user's profile picture", false),
|
||||
IDENTITY_BASIC("identity.basic", "View information about a user’s identity", false),
|
||||
IDENTITY_EMAIL("identity.email", "View a user’s email address", false),
|
||||
IDENTITY_EMAIL_READ_USER("identity.email:read:user", "This scope is not yet described.", false),
|
||||
IDENTITY_TEAM("identity.team", "View a user’s Slack workspace name", false),
|
||||
IDENTITY_TEAM_READ_USER("identity.team:read:user", "View the workspace's name, domain, and icon", false),
|
||||
IDENTITY_READ_USER("identity:read:user", "This scope is not yet described.", false),
|
||||
IM_HISTORY("im:history", "View messages and other content in direct messages that your slack app has been added to", false),
|
||||
IM_READ("im:read", "View basic information about direct messages that your slack app has been added to", false),
|
||||
IM_WRITE("im:write", "Start direct messages with people", false),
|
||||
INCOMING_WEBHOOK("incoming-webhook", "Create one-way webhooks to post messages to a specific channel", false),
|
||||
LINKS_READ("links:read", "View URLs in messages", false),
|
||||
LINKS_WRITE("links:write", "Show previews of URLs in messages", false),
|
||||
MPIM_HISTORY("mpim:history", "View messages and other content in group direct messages that your slack app has been added to", false),
|
||||
MPIM_READ("mpim:read", "View basic information about group direct messages that your slack app has been added to", false),
|
||||
MPIM_WRITE("mpim:write", "Start group direct messages with people", false),
|
||||
NONE("none", "Execute methods without needing a scope", false),
|
||||
PINS_READ("pins:read", "View pinned content in channels and conversations that your slack app has been added to", false),
|
||||
PINS_WRITE("pins:write", "Add and remove pinned messages and files", false),
|
||||
POST("post", "Post messages to a workspace", false),
|
||||
REACTIONS_READ("reactions:read", "View emoji reactions and their associated content in channels and conversations that your slack app has been added to", false),
|
||||
REACTIONS_WRITE("reactions:write", "Add and edit emoji reactions", false),
|
||||
READ("read", "View all content in a workspace", false),
|
||||
REMINDERS_READ("reminders:read", "View reminders created by your slack app", false),
|
||||
REMINDERS_READ_USER("reminders:read:user", "Access reminders created by a user or for a user", false),
|
||||
REMINDERS_WRITE("reminders:write", "Add, remove, or mark reminders as complete", false),
|
||||
REMINDERS_WRITE_USER("reminders:write:user", "Add, remove, or complete reminders for the user", false),
|
||||
REMOTE_FILES_READ("remote_files:read", "View remote files added by the app in a workspace", false),
|
||||
REMOTE_FILES_SHARE("remote_files:share", "Share remote files on a user’s behalf", false),
|
||||
REMOTE_FILES_WRITE("remote_files:write", "Add, edit, and delete remote files on a user’s behalf", false),
|
||||
SEARCH_READ("search:read", "Search a workspace’s content", false),
|
||||
STARS_READ("stars:read", "View messages and files that your slack app has starred", false),
|
||||
STARS_WRITE("stars:write", "Add or remove stars", false),
|
||||
TEAM_READ("team:read", "View the name, email domain, and icon for workspaces your slack app is connected to", false),
|
||||
TOKENS_BASIC("tokens.basic", "Execute methods without needing a scope", false),
|
||||
USERGROUPS_READ("usergroups:read", "View user groups in a workspace", false),
|
||||
USERGROUPS_WRITE("usergroups:write", "Create and manage user groups", false),
|
||||
WORKFLOW_STEPS_EXECUTE("workflow.steps:execute", "Add steps that people can use in Workflow Builder", false);
|
||||
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
@@ -22,8 +22,8 @@ public enum AuthStackoverflowScope implements AuthScope {
|
||||
WRITE_ACCESS("write_access", "perform write operations as a user", false),
|
||||
PRIVATE_INFO("private_info", "access full history of a user's private actions on the site", false);
|
||||
|
||||
private String scope;
|
||||
private String description;
|
||||
private boolean isDefault;
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package me.zhyd.oauth.enums.scope;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 企业自建应用授权范围
|
||||
*
|
||||
* @author liguanhua (347826496(a)qq.com)
|
||||
* @since 1.15.9
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum AuthWeChatEnterpriseWebScope implements AuthScope {
|
||||
/**
|
||||
* {@code scope} 含义,以{@code description} 为准
|
||||
*/
|
||||
SNSAPI_BASE("snsapi_base", "应用授权作用域。企业自建应用固定填写:snsapi_base", true);
|
||||
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
@@ -19,8 +19,8 @@ public enum AuthWechatMpScope implements AuthScope {
|
||||
SNSAPI_USERINFO("snsapi_userinfo", "弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息", true),
|
||||
SNSAPI_BASE("snsapi_base", "不弹出授权页面,直接跳转,只能获取用户openid", false);
|
||||
|
||||
private String scope;
|
||||
private String description;
|
||||
private boolean isDefault;
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ public enum AuthWeiboScope implements AuthScope {
|
||||
STATUSES_TO_ME_READ("statuses_to_me_read", "定向微博读取接口组,<a rel=\"nofollow\" href=\"http://open.weibo.com/wiki/API%E6%96%87%E6%A1%A3_V2#.E5.BE.AE.E5.8D.9A\">接口文档</a>", false),
|
||||
FOLLOW_APP_OFFICIAL_MICROBLOG("follow_app_official_microblog", "关注应用官方微博,该参数不对应具体接口,只需在应用控制台填写官方帐号即可。填写的路径:我的应用-选择自己的应用-应用信息-基本信息-官方运营账号(默认值是应用开发者帐号)", false);
|
||||
|
||||
private String scope;
|
||||
private String description;
|
||||
private boolean isDefault;
|
||||
private final String scope;
|
||||
private final String description;
|
||||
private final boolean isDefault;
|
||||
|
||||
}
|
||||
|
||||
@@ -136,15 +136,15 @@ public class Log {
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.10.0
|
||||
*/
|
||||
static class Config {
|
||||
public static class Config {
|
||||
|
||||
/**
|
||||
* 需要打印的日志级别
|
||||
*/
|
||||
static Level level = Level.DEBUG;
|
||||
public static Level level = Level.DEBUG;
|
||||
/**
|
||||
* 是否启用日志打印功能,默认启用
|
||||
*/
|
||||
static boolean enable = true;
|
||||
public static boolean enable = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* 针对JustAuth简单封装的日志打印工具,可用过{@link me.zhyd.oauth.log.Log.Config}开关日志和指定日志级别
|
||||
* 针对JustAuth简单封装的日志打印工具,可用过{@link me.zhyd.oauth.config.JustAuthLogConfig}开关日志和指定日志级别
|
||||
*/
|
||||
package me.zhyd.oauth.log;
|
||||
|
||||
@@ -19,6 +19,7 @@ public class AuthToken implements Serializable {
|
||||
private String accessToken;
|
||||
private int expireIn;
|
||||
private String refreshToken;
|
||||
private int refreshTokenExpireIn;
|
||||
private String uid;
|
||||
private String openId;
|
||||
private String accessCode;
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
package me.zhyd.oauth.request;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
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.GlobalAuthUtils;
|
||||
import me.zhyd.oauth.utils.HttpUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 钉钉登录抽象类,负责处理使用钉钉账号登录第三方网站和扫码登录第三方网站两种钉钉的登录方式
|
||||
* </p>
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.16.0
|
||||
*/
|
||||
public abstract class AbstractAuthDingtalkRequest extends AuthDefaultRequest {
|
||||
|
||||
public AbstractAuthDingtalkRequest(AuthConfig config, AuthSource source) {
|
||||
super(config, source);
|
||||
}
|
||||
|
||||
|
||||
public AbstractAuthDingtalkRequest(AuthConfig config, AuthSource source, AuthStateCache authStateCache) {
|
||||
super(config, source, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
return AuthToken.builder().accessCode(authCallback.getCode()).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||
String code = authToken.getAccessCode();
|
||||
JSONObject param = new JSONObject();
|
||||
param.put("tmp_auth_code", code);
|
||||
String response = new HttpUtils(config.getHttpConfig()).post(userInfoUrl(authToken), param.toJSONString());
|
||||
JSONObject object = JSON.parseObject(response);
|
||||
if (object.getIntValue("errcode") != 0) {
|
||||
throw new AuthException(object.getString("errmsg"));
|
||||
}
|
||||
object = object.getJSONObject("user_info");
|
||||
AuthToken token = AuthToken.builder()
|
||||
.openId(object.getString("openid"))
|
||||
.unionId(object.getString("unionid"))
|
||||
.build();
|
||||
return AuthUser.builder()
|
||||
.rawUserInfo(object)
|
||||
.uuid(object.getString("unionid"))
|
||||
.nickname(object.getString("nick"))
|
||||
.username(object.getString("nick"))
|
||||
.gender(AuthUserGender.UNKNOWN)
|
||||
.source(source.toString())
|
||||
.token(token)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("appid", config.getClientId())
|
||||
.queryParam("scope", "snsapi_login")
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回获取userInfo的url
|
||||
*
|
||||
* @param authToken 用户授权后的token
|
||||
* @return 返回获取userInfo的url
|
||||
*/
|
||||
@Override
|
||||
protected String userInfoUrl(AuthToken authToken) {
|
||||
// 根据timestamp, appSecret计算签名值
|
||||
String timestamp = System.currentTimeMillis() + "";
|
||||
String urlEncodeSignature = GlobalAuthUtils.generateDingTalkSignature(config.getClientSecret(), timestamp);
|
||||
|
||||
return UrlBuilder.fromBaseUrl(source.userInfo())
|
||||
.queryParam("signature", urlEncodeSignature)
|
||||
.queryParam("timestamp", timestamp)
|
||||
.queryParam("accessKey", config.getClientId())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
+13
-32
@@ -1,44 +1,41 @@
|
||||
package me.zhyd.oauth.request;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.utils.HttpUtils;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthDefaultSource;
|
||||
import me.zhyd.oauth.config.AuthSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.HttpUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 企业微信登录
|
||||
* 企业微信登录父类
|
||||
* </p>
|
||||
*
|
||||
* @author yangkai.shen (https://xkcoding.com)
|
||||
* @since 1.10.0
|
||||
* @author liguanhua (347826496(a)qq.com)
|
||||
* @since 1.15.9
|
||||
*/
|
||||
public class AuthWeChatEnterpriseRequest extends AuthDefaultRequest {
|
||||
public AuthWeChatEnterpriseRequest(AuthConfig config) {
|
||||
super(config, AuthDefaultSource.WECHAT_ENTERPRISE);
|
||||
public abstract class AbstractAuthWeChatEnterpriseRequest extends AuthDefaultRequest {
|
||||
|
||||
public AbstractAuthWeChatEnterpriseRequest(AuthConfig config, AuthSource source) {
|
||||
super(config,source);
|
||||
}
|
||||
|
||||
public AuthWeChatEnterpriseRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthDefaultSource.WECHAT_ENTERPRISE, authStateCache);
|
||||
|
||||
public AbstractAuthWeChatEnterpriseRequest(AuthConfig config, AuthSource source, AuthStateCache authStateCache) {
|
||||
super(config, source, authStateCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信的特殊性,此时返回的信息同时包含 openid 和 access_token
|
||||
*
|
||||
* @param authCallback 回调返回的参数
|
||||
* @return 所有信息
|
||||
*/
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
String response = doGetAuthorizationCode(accessTokenUrl(authCallback.getCode()));
|
||||
String response = doGetAuthorizationCode(accessTokenUrl(null));
|
||||
|
||||
JSONObject object = this.checkResponse(response);
|
||||
|
||||
@@ -92,22 +89,6 @@ public class AuthWeChatEnterpriseRequest extends AuthDefaultRequest {
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("appid", config.getClientId())
|
||||
.queryParam("agentid", config.getAgentId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回获取accessToken的url
|
||||
@@ -21,6 +21,8 @@ import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.StringUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* 支付宝登录
|
||||
*
|
||||
@@ -39,8 +41,21 @@ public class AuthAlipayRequest extends AuthDefaultRequest {
|
||||
|
||||
public AuthAlipayRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthDefaultSource.ALIPAY, authStateCache);
|
||||
this.alipayClient = new DefaultAlipayClient(AuthDefaultSource.ALIPAY.accessToken(), config.getClientId(), config.getClientSecret(), "json", "UTF-8", config
|
||||
.getAlipayPublicKey(), "RSA2");
|
||||
if (config.getHttpConfig() != null && config.getHttpConfig().getProxy() != null
|
||||
&& config.getHttpConfig().getProxy().address() instanceof InetSocketAddress) {
|
||||
InetSocketAddress address = (InetSocketAddress) config.getHttpConfig().getProxy().address();
|
||||
this.alipayClient = new DefaultAlipayClient(AuthDefaultSource.ALIPAY.accessToken(), config.getClientId(), config.getClientSecret(),
|
||||
"json", "UTF-8", config.getAlipayPublicKey(), "RSA2", address.getHostName(), address.getPort());
|
||||
} else {
|
||||
this.alipayClient = new DefaultAlipayClient(AuthDefaultSource.ALIPAY.accessToken(), config.getClientId(), config.getClientSecret(),
|
||||
"json", "UTF-8", config.getAlipayPublicKey(), "RSA2");
|
||||
}
|
||||
}
|
||||
|
||||
public AuthAlipayRequest(AuthConfig config, AuthStateCache authStateCache, String proxyHost, Integer proxyPort) {
|
||||
super(config, AuthDefaultSource.ALIPAY, authStateCache);
|
||||
this.alipayClient = new DefaultAlipayClient(AuthDefaultSource.ALIPAY.accessToken(), config.getClientId(), config.getClientSecret(),
|
||||
"json", "UTF-8", config.getAlipayPublicKey(), "RSA2", proxyHost, proxyPort);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -48,7 +63,7 @@ public class AuthAlipayRequest extends AuthDefaultRequest {
|
||||
AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
|
||||
request.setGrantType("authorization_code");
|
||||
request.setCode(authCallback.getAuth_code());
|
||||
AlipaySystemOauthTokenResponse response = null;
|
||||
AlipaySystemOauthTokenResponse response;
|
||||
try {
|
||||
response = this.alipayClient.execute(request);
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -8,7 +8,6 @@ import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
/**
|
||||
* 阿里云登录
|
||||
@@ -31,12 +30,12 @@ public class AuthAliyunRequest extends AuthDefaultRequest {
|
||||
String response = doPostAuthorizationCode(authCallback.getCode());
|
||||
JSONObject accessTokenObject = JSONObject.parseObject(response);
|
||||
return AuthToken.builder()
|
||||
.accessToken(accessTokenObject.getString("access_token"))
|
||||
.expireIn(accessTokenObject.getIntValue("expires_in"))
|
||||
.tokenType(accessTokenObject.getString("token_type"))
|
||||
.idToken(accessTokenObject.getString("id_token"))
|
||||
.refreshToken(accessTokenObject.getString("refresh_token"))
|
||||
.build();
|
||||
.accessToken(accessTokenObject.getString("access_token"))
|
||||
.expireIn(accessTokenObject.getIntValue("expires_in"))
|
||||
.tokenType(accessTokenObject.getString("token_type"))
|
||||
.idToken(accessTokenObject.getString("id_token"))
|
||||
.refreshToken(accessTokenObject.getString("refresh_token"))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
package me.zhyd.oauth.request;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.xkcoding.http.constants.Constants;
|
||||
import com.xkcoding.http.support.HttpHeader;
|
||||
import com.xkcoding.http.util.UrlUtil;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthDefaultSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.enums.scope.AuthAmazonScope;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.AuthScopeUtils;
|
||||
import me.zhyd.oauth.utils.HttpUtils;
|
||||
import me.zhyd.oauth.utils.PkceUtil;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Amazon登录
|
||||
* Login with Amazon for Websites Overview: https://developer.amazon.com/zh/docs/login-with-amazon/register-web.html
|
||||
* Login with Amazon SDK for JavaScript Reference Guide:https://developer.amazon.com/zh/docs/login-with-amazon/javascript-sdk-reference.html
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.16.0
|
||||
*/
|
||||
public class AuthAmazonRequest extends AuthDefaultRequest {
|
||||
|
||||
public AuthAmazonRequest(AuthConfig config) {
|
||||
super(config, AuthDefaultSource.AMAZON);
|
||||
}
|
||||
|
||||
public AuthAmazonRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthDefaultSource.AMAZON, authStateCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* https://developer.amazon.com/zh/docs/login-with-amazon/authorization-code-grant.html#authorization-request
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return String
|
||||
*/
|
||||
@Override
|
||||
public String authorize(String state) {
|
||||
UrlBuilder builder = UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("scope", this.getScopes(" ", true, AuthScopeUtils.getDefaultScopes(AuthAmazonScope.values())))
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("state", getRealState(state));
|
||||
|
||||
if (config.isPkce()) {
|
||||
String cacheKey = this.source.getName().concat(":code_verifier:").concat(config.getClientId());
|
||||
String codeVerifier = PkceUtil.generateCodeVerifier();
|
||||
String codeChallengeMethod = "S256";
|
||||
String codeChallenge = PkceUtil.generateCodeChallenge(codeChallengeMethod, codeVerifier);
|
||||
builder.queryParam("code_challenge", codeChallenge)
|
||||
.queryParam("code_challenge_method", codeChallengeMethod);
|
||||
// 缓存 codeVerifier 十分钟
|
||||
this.authStateCache.cache(cacheKey, codeVerifier, TimeUnit.MINUTES.toMillis(10));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* https://developer.amazon.com/zh/docs/login-with-amazon/authorization-code-grant.html#access-token-request
|
||||
*
|
||||
* @return access token
|
||||
*/
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
Map<String, String> form = new HashMap<>(9);
|
||||
form.put("grant_type", "authorization_code");
|
||||
form.put("code", authCallback.getCode());
|
||||
form.put("redirect_uri", config.getRedirectUri());
|
||||
form.put("client_id", config.getClientId());
|
||||
form.put("client_secret", config.getClientSecret());
|
||||
|
||||
if (config.isPkce()) {
|
||||
String cacheKey = this.source.getName().concat(":code_verifier:").concat(config.getClientId());
|
||||
String codeVerifier = this.authStateCache.get(cacheKey);
|
||||
form.put("code_verifier", codeVerifier);
|
||||
}
|
||||
return getToken(form, this.source.accessToken());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResponse refresh(AuthToken authToken) {
|
||||
Map<String, String> form = new HashMap<>(7);
|
||||
form.put("grant_type", "refresh_token");
|
||||
form.put("refresh_token", authToken.getRefreshToken());
|
||||
form.put("client_id", config.getClientId());
|
||||
form.put("client_secret", config.getClientSecret());
|
||||
return AuthResponse.builder()
|
||||
.code(AuthResponseStatus.SUCCESS.getCode())
|
||||
.data(getToken(form, this.source.refresh()))
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
private AuthToken getToken(Map<String, String> param, String url) {
|
||||
HttpHeader httpHeader = new HttpHeader();
|
||||
httpHeader.add("Host", "api.amazon.com");
|
||||
httpHeader.add(Constants.CONTENT_TYPE, "application/x-www-form-urlencoded;charset=UTF-8");
|
||||
String response = new HttpUtils(config.getHttpConfig()).post(url, param, httpHeader, false);
|
||||
JSONObject jsonObject = JSONObject.parseObject(response);
|
||||
this.checkResponse(jsonObject);
|
||||
return AuthToken.builder()
|
||||
.accessToken(jsonObject.getString("access_token"))
|
||||
.tokenType(jsonObject.getString("token_type"))
|
||||
.expireIn(jsonObject.getIntValue("expires_in"))
|
||||
.refreshToken(jsonObject.getString("refresh_token"))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验响应内容是否正确
|
||||
*
|
||||
* @param jsonObject 响应内容
|
||||
*/
|
||||
private void checkResponse(JSONObject jsonObject) {
|
||||
if (jsonObject.containsKey("error")) {
|
||||
throw new AuthException(jsonObject.getString("error_description").concat(" ") + jsonObject.getString("error_description"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* https://developer.amazon.com/zh/docs/login-with-amazon/obtain-customer-profile.html#call-profile-endpoint
|
||||
*
|
||||
* @param authToken token信息
|
||||
* @return AuthUser
|
||||
*/
|
||||
@Override
|
||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||
String accessToken = authToken.getAccessToken();
|
||||
this.checkToken(accessToken);
|
||||
|
||||
HttpHeader httpHeader = new HttpHeader();
|
||||
httpHeader.add("Host", "api.amazon.com");
|
||||
httpHeader.add("Authorization", "bearer " + accessToken);
|
||||
String userInfo = new HttpUtils(config.getHttpConfig()).get(this.source.userInfo(), new HashMap<>(0), httpHeader, false);
|
||||
JSONObject jsonObject = JSONObject.parseObject(userInfo);
|
||||
this.checkResponse(jsonObject);
|
||||
|
||||
return AuthUser.builder()
|
||||
.rawUserInfo(jsonObject)
|
||||
.uuid(jsonObject.getString("user_id"))
|
||||
.username(jsonObject.getString("name"))
|
||||
.nickname(jsonObject.getString("name"))
|
||||
.email(jsonObject.getString("email"))
|
||||
.gender(AuthUserGender.UNKNOWN)
|
||||
.source(source.toString())
|
||||
.token(authToken)
|
||||
.build();
|
||||
}
|
||||
|
||||
private void checkToken(String accessToken) {
|
||||
String tokenInfo = new HttpUtils(config.getHttpConfig()).get("https://api.amazon.com/auth/o2/tokeninfo?access_token=" + UrlUtil.urlEncode(accessToken));
|
||||
JSONObject jsonObject = JSONObject.parseObject(tokenInfo);
|
||||
if (!config.getClientId().equals(jsonObject.getString("aud"))) {
|
||||
throw new AuthException(AuthResponseStatus.ILLEGAL_TOKEN);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String userInfoUrl(AuthToken authToken) {
|
||||
return UrlBuilder.fromBaseUrl(source.userInfo())
|
||||
.queryParam("user_id", authToken.getUserId())
|
||||
.queryParam("screen_name", authToken.getScreenName())
|
||||
.queryParam("include_entities", true)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import me.zhyd.oauth.utils.AuthScopeUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
/**
|
||||
* Cooding登录
|
||||
* Coding登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.0.0
|
||||
@@ -85,7 +85,7 @@ public class AuthCodingRequest extends AuthDefaultRequest {
|
||||
*/
|
||||
@Override
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(String.format(source.authorize(), config.getCodingGroupName()))
|
||||
return UrlBuilder.fromBaseUrl(String.format(source.authorize(), config.getDomainPrefix()))
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
@@ -102,7 +102,7 @@ public class AuthCodingRequest extends AuthDefaultRequest {
|
||||
*/
|
||||
@Override
|
||||
public String accessTokenUrl(String code) {
|
||||
return UrlBuilder.fromBaseUrl(String.format(source.accessToken(), config.getCodingGroupName()))
|
||||
return UrlBuilder.fromBaseUrl(String.format(source.accessToken(), config.getDomainPrefix()))
|
||||
.queryParam("code", code)
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("client_secret", config.getClientSecret())
|
||||
@@ -119,7 +119,7 @@ public class AuthCodingRequest extends AuthDefaultRequest {
|
||||
*/
|
||||
@Override
|
||||
public String userInfoUrl(AuthToken authToken) {
|
||||
return UrlBuilder.fromBaseUrl(String.format(source.userInfo(), config.getCodingGroupName()))
|
||||
return UrlBuilder.fromBaseUrl(String.format(source.userInfo(), config.getDomainPrefix()))
|
||||
.queryParam("access_token", authToken.getAccessToken())
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ public abstract class AuthDefaultRequest implements AuthRequest {
|
||||
* @param e 具体的异常
|
||||
* @return AuthResponse
|
||||
*/
|
||||
private AuthResponse responseError(Exception e) {
|
||||
AuthResponse responseError(Exception e) {
|
||||
int errorCode = AuthResponseStatus.FAILURE.getCode();
|
||||
String errorMsg = e.getMessage();
|
||||
if (e instanceof AuthException) {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package me.zhyd.oauth.request;
|
||||
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthDefaultSource;
|
||||
|
||||
/**
|
||||
* 钉钉账号登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class AuthDingTalkAccountRequest extends AbstractAuthDingtalkRequest {
|
||||
|
||||
public AuthDingTalkAccountRequest(AuthConfig config) {
|
||||
super(config, AuthDefaultSource.DINGTALK_ACCOUNT);
|
||||
}
|
||||
|
||||
public AuthDingTalkAccountRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthDefaultSource.DINGTALK_ACCOUNT, authStateCache);
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,16 @@
|
||||
package me.zhyd.oauth.request;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.utils.HttpUtils;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthDefaultSource;
|
||||
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.GlobalAuthUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
/**
|
||||
* 钉钉登录
|
||||
* 钉钉二维码登录
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class AuthDingTalkRequest extends AuthDefaultRequest {
|
||||
public class AuthDingTalkRequest extends AbstractAuthDingtalkRequest {
|
||||
|
||||
public AuthDingTalkRequest(AuthConfig config) {
|
||||
super(config, AuthDefaultSource.DINGTALK);
|
||||
@@ -29,72 +19,4 @@ public class AuthDingTalkRequest extends AuthDefaultRequest {
|
||||
public AuthDingTalkRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthDefaultSource.DINGTALK, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
return AuthToken.builder().accessCode(authCallback.getCode()).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||
String code = authToken.getAccessCode();
|
||||
JSONObject param = new JSONObject();
|
||||
param.put("tmp_auth_code", code);
|
||||
String response = new HttpUtils(config.getHttpConfig()).post(userInfoUrl(authToken), param.toJSONString());
|
||||
JSONObject object = JSON.parseObject(response);
|
||||
if (object.getIntValue("errcode") != 0) {
|
||||
throw new AuthException(object.getString("errmsg"));
|
||||
}
|
||||
object = object.getJSONObject("user_info");
|
||||
AuthToken token = AuthToken.builder()
|
||||
.openId(object.getString("openid"))
|
||||
.unionId(object.getString("unionid"))
|
||||
.build();
|
||||
return AuthUser.builder()
|
||||
.rawUserInfo(object)
|
||||
.uuid(object.getString("unionid"))
|
||||
.nickname(object.getString("nick"))
|
||||
.username(object.getString("nick"))
|
||||
.gender(AuthUserGender.UNKNOWN)
|
||||
.source(source.toString())
|
||||
.token(token)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.9.3
|
||||
*/
|
||||
@Override
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("appid", config.getClientId())
|
||||
.queryParam("scope", "snsapi_login")
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回获取userInfo的url
|
||||
*
|
||||
* @param authToken 用户授权后的token
|
||||
* @return 返回获取userInfo的url
|
||||
*/
|
||||
@Override
|
||||
protected String userInfoUrl(AuthToken authToken) {
|
||||
// 根据timestamp, appSecret计算签名值
|
||||
String timestamp = System.currentTimeMillis() + "";
|
||||
String urlEncodeSignature = GlobalAuthUtils.generateDingTalkSignature(config.getClientSecret(), timestamp);
|
||||
|
||||
return UrlBuilder.fromBaseUrl(source.userInfo())
|
||||
.queryParam("signature", urlEncodeSignature)
|
||||
.queryParam("timestamp", timestamp)
|
||||
.queryParam("accessKey", config.getClientId())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
package me.zhyd.oauth.request;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.utils.HttpUtils;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthDefaultSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.enums.scope.AuthDouyinScope;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.AuthScopeUtils;
|
||||
import me.zhyd.oauth.utils.HttpUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
|
||||
@@ -111,7 +113,7 @@ public class AuthDouyinRequest extends AuthDefaultRequest {
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("client_key", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("scope", "user_info")
|
||||
.queryParam("scope", this.getScopes(",", true, AuthScopeUtils.getDefaultScopes(AuthDouyinScope.values())))
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ public class AuthElemeRequest extends AuthDefaultRequest {
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
Map<String, String> form = new HashMap<>(4);
|
||||
Map<String, String> form = new HashMap<>(7);
|
||||
form.put("client_id", config.getClientId());
|
||||
form.put("redirect_uri", config.getRedirectUri());
|
||||
form.put("code", authCallback.getCode());
|
||||
@@ -67,13 +67,13 @@ public class AuthElemeRequest extends AuthDefaultRequest {
|
||||
|
||||
@Override
|
||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||
Map<String, Object> parameters = new HashMap<>();
|
||||
Map<String, Object> parameters = new HashMap<>(4);
|
||||
// 获取商户账号信息的API接口名称
|
||||
String action = "eleme.user.getUser";
|
||||
// 时间戳,单位秒。API服务端允许客户端请求最大时间误差为正负5分钟。
|
||||
final long timestamp = System.currentTimeMillis();
|
||||
// 公共参数
|
||||
Map<String, Object> metasHashMap = new HashMap<>();
|
||||
Map<String, Object> metasHashMap = new HashMap<>(4);
|
||||
metasHashMap.put("app_key", config.getClientId());
|
||||
metasHashMap.put("timestamp", timestamp);
|
||||
String signature = GlobalAuthUtils.generateElemeSignature(config.getClientId(), config.getClientSecret(), timestamp, action, authToken
|
||||
@@ -118,7 +118,7 @@ public class AuthElemeRequest extends AuthDefaultRequest {
|
||||
|
||||
@Override
|
||||
public AuthResponse refresh(AuthToken oldToken) {
|
||||
Map<String, String> form = new HashMap<>(2);
|
||||
Map<String, String> form = new HashMap<>(4);
|
||||
form.put("refresh_token", oldToken.getRefreshToken());
|
||||
form.put("grant_type", "refresh_token");
|
||||
|
||||
|
||||
@@ -3,9 +3,11 @@ package me.zhyd.oauth.request;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.xkcoding.http.support.HttpHeader;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthDefaultSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
@@ -13,40 +15,63 @@ import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.GlobalAuthUtils;
|
||||
import me.zhyd.oauth.utils.HttpUtils;
|
||||
import me.zhyd.oauth.utils.StringUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
/**
|
||||
* 注意:该平台暂时存在问题,请不要使用。待修复完成后会重新发版by yadong.zhang
|
||||
* 飞书平台,企业自建应用授权登录,原逻辑由 beacon 集成于 1.14.0 版,但最新的飞书 api 已修改,并且飞书平台一直为 {@code Deprecated} 状态
|
||||
* <p>
|
||||
* 所以,最终修改该平台的实际发布版本为 1.15.9
|
||||
*
|
||||
* @author beacon
|
||||
* @since 1.14.0
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com) 重构业务逻辑 20210101
|
||||
* @since 1.15.9
|
||||
*/
|
||||
@Deprecated
|
||||
public class AuthFeishuRequest extends AuthDefaultRequest {
|
||||
|
||||
public AuthFeishuRequest(AuthConfig config) {
|
||||
super(config, AuthDefaultSource.FEISHU);
|
||||
throw new AuthException(AuthResponseStatus.FAILURE);
|
||||
}
|
||||
|
||||
public AuthFeishuRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthDefaultSource.FEISHU, authStateCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 app_access_token(企业自建应用)
|
||||
* <p>
|
||||
* Token 有效期为 2 小时,在此期间调用该接口 token 不会改变。当 token 有效期小于 30 分的时候,再次请求获取 token 的时候,
|
||||
* 会生成一个新的 token,与此同时老的 token 依然有效。
|
||||
*
|
||||
* @return appAccessToken
|
||||
*/
|
||||
private String getAppAccessToken() {
|
||||
String cacheKey = this.source.getName().concat(":app_access_token:").concat(config.getClientId());
|
||||
String cacheAppAccessToken = this.authStateCache.get(cacheKey);
|
||||
if (StringUtils.isNotEmpty(cacheAppAccessToken)) {
|
||||
return cacheAppAccessToken;
|
||||
}
|
||||
String url = "https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal/";
|
||||
JSONObject requestObject = new JSONObject();
|
||||
requestObject.put("app_id", config.getClientId());
|
||||
requestObject.put("app_secret", config.getClientSecret());
|
||||
String response = new HttpUtils(config.getHttpConfig()).post(url, requestObject.toJSONString(), new HttpHeader()
|
||||
.add("Content-Type", "application/json"));
|
||||
JSONObject jsonObject = JSON.parseObject(response);
|
||||
this.checkResponse(jsonObject);
|
||||
String appAccessToken = jsonObject.getString("app_access_token");
|
||||
// 缓存 app access token
|
||||
this.authStateCache.cache(cacheKey, appAccessToken, jsonObject.getLongValue("expire") * 1000);
|
||||
return appAccessToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
JSONObject requestObject = new JSONObject();
|
||||
requestObject.put("app_id", config.getClientId());
|
||||
requestObject.put("app_secret", config.getClientSecret());
|
||||
requestObject.put("app_access_token", this.getAppAccessToken());
|
||||
requestObject.put("grant_type", "authorization_code");
|
||||
requestObject.put("code", authCallback.getCode());
|
||||
String response = new HttpUtils(config.getHttpConfig()).post(source.accessToken(), requestObject.toJSONString(), new HttpHeader()
|
||||
.add("Content-Type", "application/json"));
|
||||
JSONObject jsonObject = JSON.parseObject(response);
|
||||
this.checkResponse(jsonObject);
|
||||
return AuthToken.builder()
|
||||
.accessToken(jsonObject.getString("access_token"))
|
||||
.refreshToken(jsonObject.getString("refresh_token"))
|
||||
.expireIn(jsonObject.getIntValue("expires_in"))
|
||||
.tokenType(jsonObject.getString("token_type"))
|
||||
.openId(jsonObject.getString("open_id"))
|
||||
.build();
|
||||
return getToken(requestObject, this.source.accessToken());
|
||||
|
||||
}
|
||||
|
||||
@@ -57,37 +82,47 @@ public class AuthFeishuRequest extends AuthDefaultRequest {
|
||||
.add("Content-Type", "application/json")
|
||||
.add("Authorization", "Bearer " + accessToken), false);
|
||||
JSONObject object = JSON.parseObject(response);
|
||||
this.checkResponse(object);
|
||||
JSONObject data = object.getJSONObject("data");
|
||||
return AuthUser.builder()
|
||||
.rawUserInfo(object)
|
||||
.avatar(object.getString("AvatarUrl"))
|
||||
.username(object.getString("Mobile"))
|
||||
.email(object.getString("Email"))
|
||||
.nickname("Name")
|
||||
.uuid(data.getString("union_id"))
|
||||
.username(data.getString("name"))
|
||||
.nickname(data.getString("name"))
|
||||
.avatar(data.getString("avatar_url"))
|
||||
.email(data.getString("email"))
|
||||
.gender(AuthUserGender.UNKNOWN)
|
||||
.token(authToken)
|
||||
.source(source.toString())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResponse refresh(AuthToken authToken) {
|
||||
JSONObject requestObject = new JSONObject();
|
||||
requestObject.put("app_id", config.getClientId());
|
||||
requestObject.put("app_secret", config.getClientSecret());
|
||||
requestObject.put("app_access_token", this.getAppAccessToken());
|
||||
requestObject.put("grant_type", "refresh_token");
|
||||
requestObject.put("refresh_token", authToken.getRefreshToken());
|
||||
String response = new HttpUtils(config.getHttpConfig()).post(source.refresh(), requestObject.toJSONString(), new HttpHeader()
|
||||
return AuthResponse.builder()
|
||||
.code(AuthResponseStatus.SUCCESS.getCode())
|
||||
.data(getToken(requestObject, this.source.refresh()))
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
private AuthToken getToken(JSONObject param, String url) {
|
||||
String response = new HttpUtils(config.getHttpConfig()).post(url, param.toJSONString(), new HttpHeader()
|
||||
.add("Content-Type", "application/json"));
|
||||
JSONObject jsonObject = JSON.parseObject(response);
|
||||
this.checkResponse(jsonObject);
|
||||
return AuthResponse.builder()
|
||||
.code(AuthResponseStatus.SUCCESS.getCode())
|
||||
.data(AuthToken.builder()
|
||||
.accessToken(jsonObject.getString("access_token"))
|
||||
.refreshToken(jsonObject.getString("refresh_token"))
|
||||
.expireIn(jsonObject.getIntValue("expires_in"))
|
||||
.tokenType(jsonObject.getString("token_type"))
|
||||
.openId(jsonObject.getString("open_id"))
|
||||
.build())
|
||||
JSONObject data = jsonObject.getJSONObject("data");
|
||||
return AuthToken.builder()
|
||||
.accessToken(data.getString("access_token"))
|
||||
.refreshToken(data.getString("refresh_token"))
|
||||
.expireIn(data.getIntValue("expires_in"))
|
||||
.tokenType(data.getString("token_type"))
|
||||
.openId(data.getString("open_id"))
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -47,7 +47,7 @@ public class AuthHuaweiRequest extends AuthDefaultRequest {
|
||||
*/
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
Map<String, String> form = new HashMap<>(5);
|
||||
Map<String, String> form = new HashMap<>(8);
|
||||
form.put("grant_type", "authorization_code");
|
||||
form.put("code", authCallback.getAuthorization_code());
|
||||
form.put("client_id", config.getClientId());
|
||||
@@ -67,7 +67,7 @@ public class AuthHuaweiRequest extends AuthDefaultRequest {
|
||||
*/
|
||||
@Override
|
||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||
Map<String, String> form = new HashMap<>(4);
|
||||
Map<String, String> form = new HashMap<>(7);
|
||||
form.put("nsp_ts", System.currentTimeMillis() + "");
|
||||
form.put("access_token", authToken.getAccessToken());
|
||||
form.put("nsp_fmt", "JS");
|
||||
@@ -100,7 +100,7 @@ public class AuthHuaweiRequest extends AuthDefaultRequest {
|
||||
*/
|
||||
@Override
|
||||
public AuthResponse refresh(AuthToken authToken) {
|
||||
Map<String, String> form = new HashMap<>(4);
|
||||
Map<String, String> form = new HashMap<>(7);
|
||||
form.put("client_id", config.getClientId());
|
||||
form.put("client_secret", config.getClientSecret());
|
||||
form.put("refresh_token", authToken.getRefreshToken());
|
||||
|
||||
@@ -41,7 +41,7 @@ public class AuthJdRequest extends AuthDefaultRequest {
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
|
||||
Map<String, String> params = new HashMap<>(5);
|
||||
Map<String, String> params = new HashMap<>(7);
|
||||
params.put("app_key", config.getClientId());
|
||||
params.put("app_secret", config.getClientSecret());
|
||||
params.put("grant_type", "authorization_code");
|
||||
@@ -104,7 +104,7 @@ public class AuthJdRequest extends AuthDefaultRequest {
|
||||
|
||||
@Override
|
||||
public AuthResponse refresh(AuthToken oldToken) {
|
||||
Map<String, String> params = new HashMap<>(5);
|
||||
Map<String, String> params = new HashMap<>(7);
|
||||
params.put("app_key", config.getClientId());
|
||||
params.put("app_secret", config.getClientSecret());
|
||||
params.put("grant_type", "refresh_token");
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
package me.zhyd.oauth.request;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.xkcoding.http.support.HttpHeader;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthDefaultSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.enums.scope.AuthLineScope;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.AuthScopeUtils;
|
||||
import me.zhyd.oauth.utils.HttpUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* LINE 登录, line.biz
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.16.0
|
||||
*/
|
||||
public class AuthLineRequest extends AuthDefaultRequest {
|
||||
|
||||
public AuthLineRequest(AuthConfig config) {
|
||||
super(config, AuthDefaultSource.LINE);
|
||||
}
|
||||
|
||||
public AuthLineRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthDefaultSource.LINE, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("grant_type", "authorization_code");
|
||||
params.put("code", authCallback.getCode());
|
||||
params.put("redirect_uri", config.getRedirectUri());
|
||||
params.put("client_id", config.getClientId());
|
||||
params.put("client_secret", config.getClientSecret());
|
||||
String response = new HttpUtils(config.getHttpConfig()).post(source.accessToken(), params, false);
|
||||
JSONObject accessTokenObject = JSONObject.parseObject(response);
|
||||
return AuthToken.builder()
|
||||
.accessToken(accessTokenObject.getString("access_token"))
|
||||
.refreshToken(accessTokenObject.getString("refresh_token"))
|
||||
.expireIn(accessTokenObject.getIntValue("expires_in"))
|
||||
.idToken(accessTokenObject.getString("id_token"))
|
||||
.scope(accessTokenObject.getString("scope"))
|
||||
.tokenType(accessTokenObject.getString("token_type"))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||
String userInfo = new HttpUtils(config.getHttpConfig()).get(source.userInfo(), null, new HttpHeader()
|
||||
.add("Content-Type", "application/x-www-form-urlencoded")
|
||||
.add("Authorization", "Bearer ".concat(authToken.getAccessToken())), false);
|
||||
JSONObject object = JSONObject.parseObject(userInfo);
|
||||
return AuthUser.builder()
|
||||
.rawUserInfo(object)
|
||||
.uuid(object.getString("userId"))
|
||||
.username(object.getString("displayName"))
|
||||
.nickname(object.getString("displayName"))
|
||||
.avatar(object.getString("pictureUrl"))
|
||||
.remark(object.getString("statusMessage"))
|
||||
.gender(AuthUserGender.UNKNOWN)
|
||||
.token(authToken)
|
||||
.source(source.toString())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResponse revoke(AuthToken authToken) {
|
||||
Map<String, String> params = new HashMap<>(5);
|
||||
params.put("access_token", authToken.getAccessToken());
|
||||
params.put("client_id", config.getClientId());
|
||||
params.put("client_secret", config.getClientSecret());
|
||||
String userInfo = new HttpUtils(config.getHttpConfig()).post(source.revoke(), params, false);
|
||||
JSONObject object = JSONObject.parseObject(userInfo);
|
||||
// 返回1表示取消授权成功,否则失败
|
||||
AuthResponseStatus status = object.getBooleanValue("revoked") ? AuthResponseStatus.SUCCESS : AuthResponseStatus.FAILURE;
|
||||
return AuthResponse.builder().code(status.getCode()).msg(status.getMsg()).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResponse refresh(AuthToken oldToken) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("grant_type", "refresh_token");
|
||||
params.put("refresh_token", oldToken.getRefreshToken());
|
||||
params.put("client_id", config.getClientId());
|
||||
params.put("client_secret", config.getClientSecret());
|
||||
String response = new HttpUtils(config.getHttpConfig()).post(source.accessToken(), params, false);
|
||||
JSONObject accessTokenObject = JSONObject.parseObject(response);
|
||||
return AuthResponse.builder()
|
||||
.code(AuthResponseStatus.SUCCESS.getCode())
|
||||
.data(AuthToken.builder()
|
||||
.accessToken(accessTokenObject.getString("access_token"))
|
||||
.refreshToken(accessTokenObject.getString("refresh_token"))
|
||||
.expireIn(accessTokenObject.getIntValue("expires_in"))
|
||||
.idToken(accessTokenObject.getString("id_token"))
|
||||
.scope(accessTokenObject.getString("scope"))
|
||||
.tokenType(accessTokenObject.getString("token_type"))
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String userInfoUrl(AuthToken authToken) {
|
||||
return UrlBuilder.fromBaseUrl(source.userInfo())
|
||||
.queryParam("user", authToken.getUid())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(super.authorize(state))
|
||||
.queryParam("nonce", state)
|
||||
.queryParam("scope", this.getScopes(" ", true, AuthScopeUtils.getDefaultScopes(AuthLineScope.values())))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ public class AuthMeituanRequest extends AuthDefaultRequest {
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
Map<String, String> form = new HashMap<>(4);
|
||||
Map<String, String> form = new HashMap<>(7);
|
||||
form.put("app_id", config.getClientId());
|
||||
form.put("secret", config.getClientSecret());
|
||||
form.put("code", authCallback.getCode());
|
||||
@@ -55,7 +55,7 @@ public class AuthMeituanRequest extends AuthDefaultRequest {
|
||||
|
||||
@Override
|
||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||
Map<String, String> form = new HashMap<>(3);
|
||||
Map<String, String> form = new HashMap<>(5);
|
||||
form.put("app_id", config.getClientId());
|
||||
form.put("secret", config.getClientSecret());
|
||||
form.put("access_token", authToken.getAccessToken());
|
||||
@@ -79,7 +79,7 @@ public class AuthMeituanRequest extends AuthDefaultRequest {
|
||||
|
||||
@Override
|
||||
public AuthResponse refresh(AuthToken oldToken) {
|
||||
Map<String, String> form = new HashMap<>(4);
|
||||
Map<String, String> form = new HashMap<>(7);
|
||||
form.put("app_id", config.getClientId());
|
||||
form.put("secret", config.getClientSecret());
|
||||
form.put("refresh_token", oldToken.getRefreshToken());
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
package me.zhyd.oauth.request;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.xkcoding.http.support.HttpHeader;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthDefaultSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.enums.scope.AuthOktaScope;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.AuthScopeUtils;
|
||||
import me.zhyd.oauth.utils.Base64Utils;
|
||||
import me.zhyd.oauth.utils.HttpUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Okta 登录
|
||||
* <p>
|
||||
* https://{domainPrefix}.okta.com/oauth2/default/.well-known/oauth-authorization-server
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.16.0
|
||||
*/
|
||||
public class AuthOktaRequest extends AuthDefaultRequest {
|
||||
|
||||
public AuthOktaRequest(AuthConfig config) {
|
||||
super(config, AuthDefaultSource.OKTA);
|
||||
}
|
||||
|
||||
public AuthOktaRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthDefaultSource.OKTA, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
String tokenUrl = accessTokenUrl(authCallback.getCode());
|
||||
return getAuthToken(tokenUrl);
|
||||
}
|
||||
|
||||
private AuthToken getAuthToken(String tokenUrl) {
|
||||
HttpHeader header = new HttpHeader()
|
||||
.add("accept", "application/json")
|
||||
.add("content-type", "application/x-www-form-urlencoded")
|
||||
.add("Authorization", "Basic " + Base64Utils.encode(config.getClientId().concat(":").concat(config.getClientSecret())));
|
||||
String response = new HttpUtils(config.getHttpConfig()).post(tokenUrl, null, header, false);
|
||||
JSONObject accessTokenObject = JSONObject.parseObject(response);
|
||||
this.checkResponse(accessTokenObject);
|
||||
return AuthToken.builder()
|
||||
.accessToken(accessTokenObject.getString("access_token"))
|
||||
.tokenType(accessTokenObject.getString("token_type"))
|
||||
.expireIn(accessTokenObject.getIntValue("expires_in"))
|
||||
.scope(accessTokenObject.getString("scope"))
|
||||
.refreshToken(accessTokenObject.getString("refresh_token"))
|
||||
.idToken(accessTokenObject.getString("id_token"))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResponse refresh(AuthToken authToken) {
|
||||
if (null == authToken.getRefreshToken()) {
|
||||
return AuthResponse.builder()
|
||||
.code(AuthResponseStatus.ILLEGAL_TOKEN.getCode())
|
||||
.msg(AuthResponseStatus.ILLEGAL_TOKEN.getMsg())
|
||||
.build();
|
||||
}
|
||||
String refreshUrl = refreshTokenUrl(authToken.getRefreshToken());
|
||||
return AuthResponse.builder()
|
||||
.code(AuthResponseStatus.SUCCESS.getCode())
|
||||
.data(this.getAuthToken(refreshUrl))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||
HttpHeader header = new HttpHeader()
|
||||
.add("Authorization", "Bearer " + authToken.getAccessToken());
|
||||
String response = new HttpUtils(config.getHttpConfig()).post(userInfoUrl(authToken), null, header, false);
|
||||
JSONObject object = JSONObject.parseObject(response);
|
||||
this.checkResponse(object);
|
||||
JSONObject address = object.getJSONObject("address");
|
||||
return AuthUser.builder()
|
||||
.rawUserInfo(object)
|
||||
.uuid(object.getString("sub"))
|
||||
.username(object.getString("name"))
|
||||
.nickname(object.getString("nickname"))
|
||||
.email(object.getString("email"))
|
||||
.location(null == address ? null : address.getString("street_address"))
|
||||
.gender(AuthUserGender.getRealGender(object.getString("sex")))
|
||||
.token(authToken)
|
||||
.source(source.toString())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResponse revoke(AuthToken authToken) {
|
||||
Map<String, String> params = new HashMap<>(4);
|
||||
params.put("token", authToken.getAccessToken());
|
||||
params.put("token_type_hint", "access_token");
|
||||
|
||||
HttpHeader header = new HttpHeader()
|
||||
.add("Authorization", "Basic " + Base64Utils.encode(config.getClientId().concat(":").concat(config.getClientSecret())));
|
||||
new HttpUtils(config.getHttpConfig()).post(revokeUrl(authToken), params, header, false);
|
||||
AuthResponseStatus status = AuthResponseStatus.SUCCESS;
|
||||
return AuthResponse.builder().code(status.getCode()).msg(status.getMsg()).build();
|
||||
}
|
||||
|
||||
private void checkResponse(JSONObject object) {
|
||||
if (object.containsKey("error")) {
|
||||
throw new AuthException(object.getString("error_description"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(String.format(source.authorize(), config.getDomainPrefix(), config.getAuthServerId()))
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("prompt", "consent")
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("scope", this.getScopes(" ", true, AuthScopeUtils.getDefaultScopes(AuthOktaScope.values())))
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String accessTokenUrl(String code) {
|
||||
return UrlBuilder.fromBaseUrl(String.format(source.accessToken(), config.getDomainPrefix(), config.getAuthServerId()))
|
||||
.queryParam("code", code)
|
||||
.queryParam("grant_type", "authorization_code")
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String refreshTokenUrl(String refreshToken) {
|
||||
return UrlBuilder.fromBaseUrl(String.format(source.refresh(), config.getDomainPrefix(), config.getAuthServerId()))
|
||||
.queryParam("refresh_token", refreshToken)
|
||||
.queryParam("grant_type", "refresh_token")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String revokeUrl(AuthToken authToken) {
|
||||
return String.format(source.revoke(), config.getDomainPrefix(), config.getAuthServerId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String userInfoUrl(AuthToken authToken) {
|
||||
return String.format(source.userInfo(), config.getDomainPrefix(), config.getAuthServerId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package me.zhyd.oauth.request;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthDefaultSource;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.enums.scope.AuthProginnScope;
|
||||
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.AuthScopeUtils;
|
||||
import me.zhyd.oauth.utils.HttpUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 程序员客栈
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.16.2
|
||||
*/
|
||||
public class AuthProginnRequest extends AuthDefaultRequest {
|
||||
|
||||
public AuthProginnRequest(AuthConfig config) {
|
||||
super(config, AuthDefaultSource.PROGINN);
|
||||
}
|
||||
|
||||
public AuthProginnRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthDefaultSource.PROGINN, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("code", authCallback.getCode());
|
||||
params.put("client_id", config.getClientId());
|
||||
params.put("client_secret", config.getClientSecret());
|
||||
params.put("grant_type", "authorization_code");
|
||||
params.put("redirect_uri", config.getRedirectUri());
|
||||
String response = new HttpUtils(config.getHttpConfig()).post(AuthDefaultSource.PROGINN.accessToken(), params, false);
|
||||
JSONObject accessTokenObject = JSONObject.parseObject(response);
|
||||
this.checkResponse(accessTokenObject);
|
||||
return AuthToken.builder()
|
||||
.accessToken(accessTokenObject.getString("access_token"))
|
||||
.refreshToken(accessTokenObject.getString("refresh_token"))
|
||||
.uid(accessTokenObject.getString("uid"))
|
||||
.tokenType(accessTokenObject.getString("token_type"))
|
||||
.expireIn(accessTokenObject.getIntValue("expires_in"))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||
String userInfo = doGetUserInfo(authToken);
|
||||
JSONObject object = JSONObject.parseObject(userInfo);
|
||||
this.checkResponse(object);
|
||||
return AuthUser.builder()
|
||||
.rawUserInfo(object)
|
||||
.uuid(object.getString("uid"))
|
||||
.username(object.getString("nickname"))
|
||||
.nickname(object.getString("nickname"))
|
||||
.avatar(object.getString("avatar"))
|
||||
.email(object.getString("email"))
|
||||
.gender(AuthUserGender.UNKNOWN)
|
||||
.token(authToken)
|
||||
.source(source.toString())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查响应内容是否正确
|
||||
*
|
||||
* @param object 请求响应内容
|
||||
*/
|
||||
private void checkResponse(JSONObject object) {
|
||||
if (object.containsKey("error")) {
|
||||
throw new AuthException(object.getString("error_description"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
*/
|
||||
@Override
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(super.authorize(state))
|
||||
.queryParam("scope", this.getScopes(" ", true, AuthScopeUtils.getDefaultScopes(AuthProginnScope.values())))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package me.zhyd.oauth.request;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.xkcoding.http.support.HttpHeader;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthDefaultSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.enums.scope.AuthSlackScope;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.AuthScopeUtils;
|
||||
import me.zhyd.oauth.utils.HttpUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
/**
|
||||
* slack登录, slack.com
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @since 1.16.0
|
||||
*/
|
||||
public class AuthSlackRequest extends AuthDefaultRequest {
|
||||
|
||||
public AuthSlackRequest(AuthConfig config) {
|
||||
super(config, AuthDefaultSource.SLACK);
|
||||
}
|
||||
|
||||
public AuthSlackRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthDefaultSource.SLACK, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
HttpHeader header = new HttpHeader()
|
||||
.add("Content-Type", "application/x-www-form-urlencoded");
|
||||
String response = new HttpUtils(config.getHttpConfig()).get(accessTokenUrl(authCallback.getCode()), null, header, false);
|
||||
JSONObject accessTokenObject = JSONObject.parseObject(response);
|
||||
this.checkResponse(accessTokenObject);
|
||||
return AuthToken.builder()
|
||||
.accessToken(accessTokenObject.getString("access_token"))
|
||||
.scope(accessTokenObject.getString("scope"))
|
||||
.tokenType(accessTokenObject.getString("token_type"))
|
||||
.uid(accessTokenObject.getJSONObject("authed_user").getString("id"))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||
HttpHeader header = new HttpHeader()
|
||||
.add("Content-Type", "application/x-www-form-urlencoded")
|
||||
.add("Authorization", "Bearer ".concat(authToken.getAccessToken()));
|
||||
String userInfo = new HttpUtils(config.getHttpConfig()).get(userInfoUrl(authToken), null, header, false);
|
||||
JSONObject object = JSONObject.parseObject(userInfo);
|
||||
this.checkResponse(object);
|
||||
JSONObject user = object.getJSONObject("user");
|
||||
JSONObject profile = user.getJSONObject("profile");
|
||||
return AuthUser.builder()
|
||||
.rawUserInfo(user)
|
||||
.uuid(user.getString("id"))
|
||||
.username(user.getString("name"))
|
||||
.nickname(user.getString("real_name"))
|
||||
.avatar(profile.getString("image_original"))
|
||||
.email(profile.getString("email"))
|
||||
.gender(AuthUserGender.UNKNOWN)
|
||||
.token(authToken)
|
||||
.source(source.toString())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResponse revoke(AuthToken authToken) {
|
||||
HttpHeader header = new HttpHeader()
|
||||
.add("Content-Type", "application/x-www-form-urlencoded")
|
||||
.add("Authorization", "Bearer ".concat(authToken.getAccessToken()));
|
||||
String userInfo = new HttpUtils(config.getHttpConfig()).get(source.revoke(), null, header, false);
|
||||
JSONObject object = JSONObject.parseObject(userInfo);
|
||||
this.checkResponse(object);
|
||||
// 返回1表示取消授权成功,否则失败
|
||||
AuthResponseStatus status = object.getBooleanValue("revoked") ? AuthResponseStatus.SUCCESS : AuthResponseStatus.FAILURE;
|
||||
return AuthResponse.builder().code(status.getCode()).msg(status.getMsg()).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查响应内容是否正确
|
||||
*
|
||||
* @param object 请求响应内容
|
||||
*/
|
||||
private void checkResponse(JSONObject object) {
|
||||
if (!object.getBooleanValue("ok")) {
|
||||
String errorMsg = object.getString("error");
|
||||
if (object.containsKey("response_metadata")) {
|
||||
JSONArray array = object.getJSONObject("response_metadata").getJSONArray("messages");
|
||||
if (null != array && array.size() > 0) {
|
||||
errorMsg += "; " + String.join(",", array.toArray(new String[0]));
|
||||
}
|
||||
}
|
||||
|
||||
throw new AuthException(errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String userInfoUrl(AuthToken authToken) {
|
||||
return UrlBuilder.fromBaseUrl(source.userInfo())
|
||||
.queryParam("user", authToken.getUid())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
*/
|
||||
@Override
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("state", getRealState(state))
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("scope", this.getScopes(",", true, AuthScopeUtils.getDefaultScopes(AuthSlackScope.values())))
|
||||
.build();
|
||||
}
|
||||
|
||||
@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("redirect_uri", config.getRedirectUri())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,16 @@ import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthDefaultSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.enums.AuthUserGender;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.GlobalAuthUtils;
|
||||
import me.zhyd.oauth.utils.HttpUtils;
|
||||
import me.zhyd.oauth.utils.StringUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
/**
|
||||
@@ -33,6 +37,26 @@ public class AuthTaobaoRequest extends AuthDefaultRequest {
|
||||
return AuthToken.builder().accessCode(authCallback.getCode()).build();
|
||||
}
|
||||
|
||||
private AuthToken getAuthToken(JSONObject object) {
|
||||
this.checkResponse(object);
|
||||
|
||||
return AuthToken.builder()
|
||||
.accessToken(object.getString("access_token"))
|
||||
.expireIn(object.getIntValue("expires_in"))
|
||||
.tokenType(object.getString("token_type"))
|
||||
.idToken(object.getString("id_token"))
|
||||
.refreshToken(object.getString("refresh_token"))
|
||||
.uid(object.getString("taobao_user_id"))
|
||||
.openId(object.getString("taobao_open_uid"))
|
||||
.build();
|
||||
}
|
||||
|
||||
private void checkResponse(JSONObject object) {
|
||||
if (object.containsKey("error")) {
|
||||
throw new AuthException(object.getString("error_description"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||
String response = doPostAuthorizationCode(authToken.getAccessCode());
|
||||
@@ -40,16 +64,12 @@ public class AuthTaobaoRequest extends AuthDefaultRequest {
|
||||
if (accessTokenObject.containsKey("error")) {
|
||||
throw new AuthException(accessTokenObject.getString("error_description"));
|
||||
}
|
||||
authToken.setAccessToken(accessTokenObject.getString("access_token"));
|
||||
authToken.setRefreshToken(accessTokenObject.getString("refresh_token"));
|
||||
authToken.setExpireIn(accessTokenObject.getIntValue("expires_in"));
|
||||
authToken.setUid(accessTokenObject.getString("taobao_user_id"));
|
||||
authToken.setOpenId(accessTokenObject.getString("taobao_open_uid"));
|
||||
authToken = this.getAuthToken(accessTokenObject);
|
||||
|
||||
String nick = GlobalAuthUtils.urlDecode(accessTokenObject.getString("taobao_user_nick"));
|
||||
return AuthUser.builder()
|
||||
.rawUserInfo(new JSONObject())
|
||||
.uuid(accessTokenObject.getString("taobao_user_id"))
|
||||
.rawUserInfo(accessTokenObject)
|
||||
.uuid(StringUtils.isEmpty(authToken.getUid()) ? authToken.getOpenId() : authToken.getUid())
|
||||
.username(nick)
|
||||
.nickname(nick)
|
||||
.gender(AuthUserGender.UNKNOWN)
|
||||
@@ -58,6 +78,17 @@ public class AuthTaobaoRequest extends AuthDefaultRequest {
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResponse refresh(AuthToken oldToken) {
|
||||
String tokenUrl = refreshTokenUrl(oldToken.getRefreshToken());
|
||||
String response = new HttpUtils(config.getHttpConfig()).post(tokenUrl);
|
||||
JSONObject accessTokenObject = JSONObject.parseObject(response);
|
||||
return AuthResponse.builder()
|
||||
.code(AuthResponseStatus.SUCCESS.getCode())
|
||||
.data(this.getAuthToken(accessTokenObject))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
|
||||
@@ -39,7 +39,7 @@ public class AuthTeambitionRequest extends AuthDefaultRequest {
|
||||
*/
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
Map<String, String> form = new HashMap<>(4);
|
||||
Map<String, String> form = new HashMap<>(7);
|
||||
form.put("client_id", config.getClientId());
|
||||
form.put("client_secret", config.getClientSecret());
|
||||
form.put("code", authCallback.getCode());
|
||||
@@ -90,7 +90,7 @@ public class AuthTeambitionRequest extends AuthDefaultRequest {
|
||||
String uid = oldToken.getUid();
|
||||
String refreshToken = oldToken.getRefreshToken();
|
||||
|
||||
Map<String, String> form = new HashMap<>(2);
|
||||
Map<String, String> form = new HashMap<>(4);
|
||||
form.put("_userId", uid);
|
||||
form.put("refresh_token", refreshToken);
|
||||
String response = new HttpUtils(config.getHttpConfig()).post(source.refresh(), form, false);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package me.zhyd.oauth.request;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.utils.HttpUtils;
|
||||
import com.xkcoding.http.constants.Constants;
|
||||
import com.xkcoding.http.support.HttpHeader;
|
||||
import com.xkcoding.http.util.MapUtil;
|
||||
@@ -11,6 +10,7 @@ import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.GlobalAuthUtils;
|
||||
import me.zhyd.oauth.utils.HttpUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -47,7 +47,7 @@ public class AuthTwitterRequest extends AuthDefaultRequest {
|
||||
*/
|
||||
@Override
|
||||
public String authorize(String state) {
|
||||
AuthToken token = this.getRequestToken();
|
||||
AuthToken token = this.getRequestToken();
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("oauth_token", token.getOauthToken())
|
||||
.build();
|
||||
@@ -102,7 +102,7 @@ public class AuthTwitterRequest extends AuthDefaultRequest {
|
||||
httpHeader.add("Authorization", header);
|
||||
httpHeader.add(Constants.CONTENT_TYPE, "application/x-www-form-urlencoded");
|
||||
|
||||
Map<String, String> form = new HashMap<>(1);
|
||||
Map<String, String> form = new HashMap<>(3);
|
||||
form.put("oauth_verifier", authCallback.getOauth_verifier());
|
||||
String response = new HttpUtils(config.getHttpConfig()).post(source.accessToken(), form, httpHeader, false);
|
||||
|
||||
@@ -118,18 +118,16 @@ public class AuthTwitterRequest extends AuthDefaultRequest {
|
||||
|
||||
@Override
|
||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||
Map<String, String> queryParams = new HashMap<>();
|
||||
queryParams.put("user_id", authToken.getUserId());
|
||||
queryParams.put("screen_name", authToken.getScreenName());
|
||||
Map<String, String> queryParams = new HashMap<>(5);
|
||||
queryParams.put("include_entities", Boolean.toString(true));
|
||||
queryParams.put("include_email", Boolean.toString(true));
|
||||
|
||||
Map<String, String> oauthParams = buildOauthParams();
|
||||
oauthParams.put("oauth_token", authToken.getOauthToken());
|
||||
|
||||
Map<String, String> params = new HashMap<>(oauthParams);
|
||||
params.putAll(queryParams);
|
||||
oauthParams.put("oauth_signature", generateTwitterSignature(params, "GET", source.userInfo(), config.getClientSecret(), authToken
|
||||
.getOauthTokenSecret()));
|
||||
oauthParams.put("oauth_signature", generateTwitterSignature(params, "GET", source.userInfo(), config.getClientSecret(), authToken.getOauthTokenSecret()));
|
||||
String header = buildHeader(oauthParams);
|
||||
|
||||
HttpHeader httpHeader = new HttpHeader();
|
||||
@@ -147,6 +145,7 @@ public class AuthTwitterRequest extends AuthDefaultRequest {
|
||||
.blog(userInfo.getString("url"))
|
||||
.location(userInfo.getString("location"))
|
||||
.avatar(userInfo.getString("profile_image_url"))
|
||||
.email(userInfo.getString("email"))
|
||||
.source(source.toString())
|
||||
.token(authToken)
|
||||
.build();
|
||||
@@ -155,14 +154,13 @@ public class AuthTwitterRequest extends AuthDefaultRequest {
|
||||
@Override
|
||||
protected String userInfoUrl(AuthToken authToken) {
|
||||
return UrlBuilder.fromBaseUrl(source.userInfo())
|
||||
.queryParam("user_id", authToken.getUserId())
|
||||
.queryParam("screen_name", authToken.getScreenName())
|
||||
.queryParam("include_entities", true)
|
||||
.queryParam("include_email", true)
|
||||
.build();
|
||||
}
|
||||
|
||||
private Map<String, String> buildOauthParams() {
|
||||
Map<String, String> params = new HashMap<>(5);
|
||||
Map<String, String> params = new HashMap<>(12);
|
||||
params.put("oauth_consumer_key", config.getClientId());
|
||||
params.put("oauth_nonce", GlobalAuthUtils.generateNonce(32));
|
||||
params.put("oauth_signature_method", "HMAC-SHA1");
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package me.zhyd.oauth.request;
|
||||
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthDefaultSource;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 企业微信二维码登录
|
||||
* </p>
|
||||
*
|
||||
* @author yangkai.shen (https://xkcoding.com)
|
||||
* @author liguanhua (347826496(a)qq.com) 重构该类,将通用方法提取
|
||||
* @author lyadong.zhang (yadong.zhang0415(a)gmail.com) 修改类名
|
||||
* @since 1.10.0
|
||||
*/
|
||||
public class AuthWeChatEnterpriseQrcodeRequest extends AbstractAuthWeChatEnterpriseRequest {
|
||||
public AuthWeChatEnterpriseQrcodeRequest(AuthConfig config) {
|
||||
super(config, AuthDefaultSource.WECHAT_ENTERPRISE);
|
||||
}
|
||||
|
||||
public AuthWeChatEnterpriseQrcodeRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthDefaultSource.WECHAT_ENTERPRISE, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("appid", config.getClientId())
|
||||
.queryParam("agentid", config.getAgentId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("state", getRealState(state))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package me.zhyd.oauth.request;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthDefaultSource;
|
||||
import me.zhyd.oauth.enums.AuthResponseStatus;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.log.Log;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.utils.*;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 企业微信第三方二维码登录
|
||||
* </p>
|
||||
*
|
||||
* @author zhengjx
|
||||
* @since 1.16.3
|
||||
*/
|
||||
public class AuthWeChatEnterpriseThirdQrcodeRequest extends AbstractAuthWeChatEnterpriseRequest {
|
||||
public AuthWeChatEnterpriseThirdQrcodeRequest(AuthConfig config) {
|
||||
super(config, AuthDefaultSource.WECHAT_ENTERPRISE_QRCODE_THIRD);
|
||||
}
|
||||
|
||||
public AuthWeChatEnterpriseThirdQrcodeRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthDefaultSource.WECHAT_ENTERPRISE_QRCODE_THIRD, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("appid", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("state", getRealState(state))
|
||||
.queryParam("usertype", config.getUsertype())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResponse login(AuthCallback authCallback) {
|
||||
try {
|
||||
if (!config.isIgnoreCheckState()) {
|
||||
AuthChecker.checkState(authCallback.getState(), source, authStateCache);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
try {
|
||||
String response = doGetAuthorizationCode(accessTokenUrl());
|
||||
JSONObject object = this.checkResponse(response);
|
||||
AuthToken authToken = AuthToken.builder()
|
||||
.accessToken(object.getString("provider_access_token"))
|
||||
.expireIn(object.getIntValue("expires_in"))
|
||||
.build();
|
||||
return authToken;
|
||||
} catch (Exception e) {
|
||||
throw new AuthException("企业微信获取token失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doGetAuthorizationCode(String code) {
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("corpid", config.getClientId());
|
||||
data.put("provider_secret", config.getClientSecret());
|
||||
return new HttpUtils(config.getHttpConfig()).post(accessTokenUrl(code), data.toJSONString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取token的URL
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected String accessTokenUrl() {
|
||||
return UrlBuilder.fromBaseUrl(source.accessToken())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||
JSONObject response = this.checkResponse(doGetUserInfo(authToken));
|
||||
return AuthUser.builder()
|
||||
.rawUserInfo(response)
|
||||
.build();
|
||||
}
|
||||
|
||||
protected String doGetUserInfo(AuthToken authToken) {
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("auth_code", authToken.getCode());
|
||||
return new HttpUtils(config.getHttpConfig())
|
||||
.post(userInfoUrl(authToken), data.toJSONString());
|
||||
}
|
||||
|
||||
protected String userInfoUrl(AuthToken authToken) {
|
||||
return UrlBuilder.fromBaseUrl(source.userInfo())
|
||||
.queryParam("access_token", authToken.getAccessToken()).
|
||||
build();
|
||||
}
|
||||
|
||||
private JSONObject checkResponse(String response) {
|
||||
JSONObject object = JSONObject.parseObject(response);
|
||||
if (object.containsKey("errcode") && object.getIntValue("errcode") != 0) {
|
||||
throw new AuthException(object.getString("errmsg"), source);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package me.zhyd.oauth.request;
|
||||
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthDefaultSource;
|
||||
import me.zhyd.oauth.enums.scope.AuthWeChatEnterpriseWebScope;
|
||||
import me.zhyd.oauth.utils.AuthScopeUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 企业微信网页登录
|
||||
* </p>
|
||||
*
|
||||
* @author liguanhua (347826496(a)qq.com)
|
||||
* @since 1.15.9
|
||||
*/
|
||||
public class AuthWeChatEnterpriseWebRequest extends AbstractAuthWeChatEnterpriseRequest {
|
||||
public AuthWeChatEnterpriseWebRequest(AuthConfig config) {
|
||||
super(config, AuthDefaultSource.WECHAT_ENTERPRISE_WEB);
|
||||
}
|
||||
|
||||
public AuthWeChatEnterpriseWebRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthDefaultSource.WECHAT_ENTERPRISE_WEB, authStateCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("appid", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("scope", this.getScopes(",", false, AuthScopeUtils.getDefaultScopes(AuthWeChatEnterpriseWebScope.values())))
|
||||
.queryParam("state", getRealState(state).concat("#wechat_redirect"))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package me.zhyd.oauth.request;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.xkcoding.http.HttpUtil;
|
||||
import me.zhyd.oauth.cache.AuthStateCache;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthDefaultSource;
|
||||
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.GlobalAuthUtils;
|
||||
import me.zhyd.oauth.utils.UrlBuilder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* 喜马拉雅登录
|
||||
*
|
||||
* @author zwzch (zwzch4j@gmail.com)
|
||||
* @since 1.15.9
|
||||
*/
|
||||
public class AuthXmlyRequest extends AuthDefaultRequest {
|
||||
|
||||
public AuthXmlyRequest(AuthConfig config) {
|
||||
super(config, AuthDefaultSource.XMLY);
|
||||
}
|
||||
|
||||
public AuthXmlyRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||
super(config, AuthDefaultSource.XMLY, authStateCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取access token
|
||||
*
|
||||
* @param authCallback 授权成功后的回调参数
|
||||
* @return token
|
||||
* @see AuthDefaultRequest#authorize(String)
|
||||
*/
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
Map<String, String> map = new HashMap<>(9);
|
||||
map.put("code", authCallback.getCode());
|
||||
map.put("client_id", config.getClientId());
|
||||
map.put("client_secret", config.getClientSecret());
|
||||
map.put("device_id", config.getDeviceId());
|
||||
map.put("grant_type", "authorization_code");
|
||||
map.put("redirect_uri", config.getRedirectUri());
|
||||
String response = HttpUtil.post(source.accessToken(), map, true);
|
||||
JSONObject accessTokenObject = JSONObject.parseObject(response);
|
||||
this.checkResponse(accessTokenObject);
|
||||
|
||||
return AuthToken.builder()
|
||||
.accessToken(accessTokenObject.getString("access_token"))
|
||||
.refreshToken(accessTokenObject.getString("refresh_token"))
|
||||
.expireIn(accessTokenObject.getIntValue("expires_in"))
|
||||
.uid(accessTokenObject.getString("uid"))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
||||
*
|
||||
* @param state state 验证授权流程的参数,可以防止csrf
|
||||
* @return 返回授权地址
|
||||
* @since 1.15.8
|
||||
*/
|
||||
@Override
|
||||
public String authorize(String state) {
|
||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||
.queryParam("response_type", "code")
|
||||
.queryParam("client_id", config.getClientId())
|
||||
.queryParam("redirect_uri", config.getRedirectUri())
|
||||
.queryParam("state", getRealState(state))
|
||||
.queryParam("client_os_type", "3")
|
||||
.queryParam("device_id", config.getDeviceId())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用token换取用户信息
|
||||
*
|
||||
* @param authToken token信息
|
||||
* @return 用户信息
|
||||
* @see AuthDefaultRequest#getAccessToken(AuthCallback)
|
||||
*/
|
||||
@Override
|
||||
public AuthUser getUserInfo(AuthToken authToken) {
|
||||
Map<String, String> map = new TreeMap<>();
|
||||
map.put("app_key", config.getClientId());
|
||||
map.put("client_os_type", Optional.ofNullable(config.getClientOsType()).orElse(3).toString());
|
||||
map.put("device_id", config.getDeviceId());
|
||||
map.put("pack_id", config.getPackId());
|
||||
map.put("access_token", authToken.getAccessToken());
|
||||
map.put("sig", GlobalAuthUtils.generateXmlySignature(map, config.getClientSecret()));
|
||||
String rawUserInfo = HttpUtil.get(source.userInfo(), map, false);
|
||||
JSONObject object = JSONObject.parseObject(rawUserInfo);
|
||||
checkResponse(object);
|
||||
return AuthUser.builder()
|
||||
.uuid(object.getString("id"))
|
||||
.nickname(object.getString("nickname"))
|
||||
.avatar(object.getString("avatar_url"))
|
||||
.rawUserInfo(object)
|
||||
.source(source.toString())
|
||||
.token(authToken)
|
||||
.gender(AuthUserGender.UNKNOWN)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验响应结果
|
||||
*
|
||||
* @param object 接口返回的结果
|
||||
*/
|
||||
private void checkResponse(JSONObject object) {
|
||||
if (object.containsKey("errcode")) {
|
||||
throw new AuthException(object.getIntValue("error_no"), object.getString("error_desc"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,8 @@ public class AuthChecker {
|
||||
* @since 1.6.1-beta
|
||||
*/
|
||||
public static boolean isSupportedAuth(AuthConfig config, AuthSource source) {
|
||||
boolean isSupported = StringUtils.isNotEmpty(config.getClientId()) && StringUtils.isNotEmpty(config.getClientSecret()) && StringUtils.isNotEmpty(config.getRedirectUri());
|
||||
boolean isSupported = StringUtils.isNotEmpty(config.getClientId())
|
||||
&& StringUtils.isNotEmpty(config.getClientSecret());
|
||||
if (isSupported && AuthDefaultSource.ALIPAY == source) {
|
||||
isSupported = StringUtils.isNotEmpty(config.getAlipayPublicKey());
|
||||
}
|
||||
@@ -35,8 +36,14 @@ public class AuthChecker {
|
||||
if (isSupported && AuthDefaultSource.WECHAT_ENTERPRISE == source) {
|
||||
isSupported = StringUtils.isNotEmpty(config.getAgentId());
|
||||
}
|
||||
if (isSupported && AuthDefaultSource.CODING == source) {
|
||||
isSupported = StringUtils.isNotEmpty(config.getCodingGroupName());
|
||||
if (isSupported && (AuthDefaultSource.CODING == source || AuthDefaultSource.OKTA == source)) {
|
||||
isSupported = StringUtils.isNotEmpty(config.getDomainPrefix());
|
||||
}
|
||||
if (isSupported && AuthDefaultSource.XMLY == source) {
|
||||
isSupported = StringUtils.isNotEmpty(config.getDeviceId()) && null != config.getClientOsType();
|
||||
if (isSupported) {
|
||||
isSupported = config.getClientOsType() == 3 || StringUtils.isNotEmpty(config.getPackId());
|
||||
}
|
||||
}
|
||||
return isSupported;
|
||||
}
|
||||
@@ -50,6 +57,12 @@ public class AuthChecker {
|
||||
*/
|
||||
public static void checkConfig(AuthConfig config, AuthSource source) {
|
||||
String redirectUri = config.getRedirectUri();
|
||||
if (config.isIgnoreCheckRedirectUri()) {
|
||||
return;
|
||||
}
|
||||
if (StringUtils.isEmpty(redirectUri)) {
|
||||
throw new AuthException(AuthResponseStatus.ILLEGAL_REDIRECT_URI, source);
|
||||
}
|
||||
if (!GlobalAuthUtils.isHttpProtocol(redirectUri) && !GlobalAuthUtils.isHttpsProtocol(redirectUri)) {
|
||||
throw new AuthException(AuthResponseStatus.ILLEGAL_REDIRECT_URI, source);
|
||||
}
|
||||
|
||||
@@ -101,15 +101,18 @@ public class GlobalAuthUtils {
|
||||
* @return map
|
||||
*/
|
||||
public static Map<String, String> parseStringToMap(String accessTokenStr) {
|
||||
Map<String, String> res = new HashMap<>(6);
|
||||
Map<String, String> res = null;
|
||||
if (accessTokenStr.contains("&")) {
|
||||
String[] fields = accessTokenStr.split("&");
|
||||
res = new HashMap<>((int) (fields.length / 0.75 + 1));
|
||||
for (String field : fields) {
|
||||
if (field.contains("=")) {
|
||||
String[] keyValue = field.split("=");
|
||||
res.put(GlobalAuthUtils.urlDecode(keyValue[0]), keyValue.length == 2 ? GlobalAuthUtils.urlDecode(keyValue[1]) : null);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res = new HashMap<>(0);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -146,7 +149,7 @@ public class GlobalAuthUtils {
|
||||
if (StringUtils.isEmpty(url)) {
|
||||
return false;
|
||||
}
|
||||
return url.startsWith("http://");
|
||||
return url.startsWith("http://") || url.startsWith("http%3A%2F%2F");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,7 +162,7 @@ public class GlobalAuthUtils {
|
||||
if (StringUtils.isEmpty(url)) {
|
||||
return false;
|
||||
}
|
||||
return url.startsWith("https://");
|
||||
return url.startsWith("https://") || url.startsWith("https%3A%2F%2F");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -220,6 +223,34 @@ public class GlobalAuthUtils {
|
||||
return new String(Base64Utils.encode(signature, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* 喜马拉雅签名算法
|
||||
* {@code https://open.ximalaya.com/doc/detailApi?categoryId=6&articleId=69}
|
||||
*
|
||||
* @param params 加密参数
|
||||
* @param clientSecret 平台应用的授权key
|
||||
* @return Signature
|
||||
* @since 1.15.9
|
||||
*/
|
||||
public static String generateXmlySignature(Map<String, String> params, String clientSecret) {
|
||||
TreeMap<String, String> map = new TreeMap<>(params);
|
||||
String baseStr = Base64Utils.encode(parseMapToString(map, false));
|
||||
byte[] sign = sign(clientSecret.getBytes(DEFAULT_ENCODING), baseStr.getBytes(DEFAULT_ENCODING), HMAC_SHA1);
|
||||
MessageDigest md5 = null;
|
||||
StringBuilder builder = null;
|
||||
try {
|
||||
builder = new StringBuilder();
|
||||
md5 = MessageDigest.getInstance("MD5");
|
||||
md5.update(sign);
|
||||
byte[] byteData = md5.digest();
|
||||
for (byte byteDatum : byteData) {
|
||||
builder.append(Integer.toString((byteDatum & 0xff) + 0x100, 16).substring(1));
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return null == builder ? "" : builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成饿了么请求的Signature
|
||||
* <p>
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package me.zhyd.oauth.utils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* 该配置仅用于支持 PKCE 模式的平台,针对无服务应用,不推荐使用隐式授权,推荐使用 PKCE 模式
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class PkceUtil {
|
||||
|
||||
public static String generateCodeVerifier() {
|
||||
String randomStr = RandomUtil.randomString(50);
|
||||
return Base64Utils.encodeUrlSafe(randomStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 适用于 OAuth 2.0 PKCE 增强协议
|
||||
*
|
||||
* @param codeChallengeMethod s256 / plain
|
||||
* @param codeVerifier 客户端生产的校验码
|
||||
* @return code challenge
|
||||
*/
|
||||
public static String generateCodeChallenge(String codeChallengeMethod, String codeVerifier) {
|
||||
if ("S256".equalsIgnoreCase(codeChallengeMethod)) {
|
||||
// https://tools.ietf.org/html/rfc7636#section-4.2
|
||||
// code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
|
||||
return newStringUsAscii(Base64Utils.encodeUrlSafe(Sha256.digest(codeVerifier), true));
|
||||
} else {
|
||||
return codeVerifier;
|
||||
}
|
||||
}
|
||||
|
||||
public static String newStringUsAscii(byte[] bytes) {
|
||||
return new String(bytes, StandardCharsets.US_ASCII);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package me.zhyd.oauth.utils;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* 生成随机字符串
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.16.0
|
||||
*/
|
||||
public class RandomUtil {
|
||||
|
||||
/**
|
||||
* 用于随机选的字符和数字
|
||||
*/
|
||||
public static final String BASE_CHAR_NUMBER = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
|
||||
/**
|
||||
* 获得一个随机的字符串
|
||||
*
|
||||
* @param length 字符串的长度
|
||||
* @return 指定长度的随机字符串
|
||||
*/
|
||||
public static String randomString(int length) {
|
||||
final StringBuilder sb = new StringBuilder(length);
|
||||
|
||||
if (length < 1) {
|
||||
length = 1;
|
||||
}
|
||||
int baseLength = BASE_CHAR_NUMBER.length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
int number = ThreadLocalRandom.current().nextInt(baseLength);
|
||||
sb.append(BASE_CHAR_NUMBER.charAt(number));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package me.zhyd.oauth.utils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* SHA256 加密
|
||||
*
|
||||
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
|
||||
* @version 1.0.0
|
||||
* @since 1.16.0
|
||||
*/
|
||||
public class Sha256 {
|
||||
|
||||
public static byte[] digest(String str) {
|
||||
MessageDigest messageDigest;
|
||||
try {
|
||||
messageDigest = MessageDigest.getInstance("SHA-256");
|
||||
messageDigest.update(str.getBytes(StandardCharsets.UTF_8));
|
||||
return messageDigest.digest();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package me.zhyd.oauth;
|
||||
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.config.AuthDefaultSource;
|
||||
import me.zhyd.oauth.config.AuthExtendSource;
|
||||
import me.zhyd.oauth.request.AuthExtendRequest;
|
||||
import me.zhyd.oauth.request.AuthGiteeRequest;
|
||||
import me.zhyd.oauth.request.AuthGithubRequest;
|
||||
import me.zhyd.oauth.request.AuthRequest;
|
||||
import me.zhyd.oauth.utils.AuthStateUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class AuthRequestBuilderTest {
|
||||
|
||||
/**
|
||||
* 示例:一般场景下通过 AuthRequestBuilder 构建 AuthRequest
|
||||
*/
|
||||
@Test
|
||||
public void build2() {
|
||||
AuthRequest authRequest = AuthRequestBuilder.builder()
|
||||
.source("github")
|
||||
.authConfig(AuthConfig.builder()
|
||||
.clientId("a")
|
||||
.clientSecret("a")
|
||||
.redirectUri("https://www.justauth.cn")
|
||||
.build())
|
||||
.build();
|
||||
Assert.assertTrue(authRequest instanceof AuthGithubRequest);
|
||||
System.out.println(authRequest.authorize(AuthStateUtils.createState()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 示例:AuthConfig 需要动态获取的场景下通过 AuthRequestBuilder 构建 AuthRequest
|
||||
*/
|
||||
@Test
|
||||
public void build() {
|
||||
AuthRequest authRequest = AuthRequestBuilder.builder()
|
||||
.source("gitee")
|
||||
.authConfig((source) -> {
|
||||
// 通过 source 动态获取 AuthConfig
|
||||
// 此处可以灵活的从 sql 中取配置也可以从配置文件中取配置
|
||||
return AuthConfig.builder()
|
||||
.clientId(source)
|
||||
.clientSecret(source)
|
||||
.redirectUri("https://www.justauth.cn/" + source)
|
||||
.build();
|
||||
})
|
||||
.build();
|
||||
Assert.assertTrue(authRequest instanceof AuthGiteeRequest);
|
||||
System.out.println(authRequest.authorize(AuthStateUtils.createState()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 示例:自定义实现的 AuthRequest,通过 AuthRequestBuilder 构建 AuthRequest
|
||||
*/
|
||||
@Test
|
||||
public void build3() {
|
||||
AuthRequest authRequest = AuthRequestBuilder.builder()
|
||||
// 关键点:将自定义的 AuthSource 配置上
|
||||
.extendSource(AuthExtendSource.values())
|
||||
.source("other")
|
||||
.authConfig(AuthConfig.builder()
|
||||
.clientId("a")
|
||||
.clientSecret("a")
|
||||
.redirectUri("https://www.justauth.cn")
|
||||
.build())
|
||||
.build();
|
||||
Assert.assertTrue(authRequest instanceof AuthExtendRequest);
|
||||
System.out.println(authRequest.authorize(AuthStateUtils.createState()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试不同平台
|
||||
*/
|
||||
@Test
|
||||
public void build4() {
|
||||
for (AuthDefaultSource value : AuthDefaultSource.values()) {
|
||||
if (value == AuthDefaultSource.TWITTER) {
|
||||
System.out.println(value.getTargetClass());
|
||||
System.out.println("忽略 twitter");
|
||||
continue;
|
||||
}
|
||||
AuthRequest authRequest = AuthRequestBuilder.builder()
|
||||
.source(value.getName())
|
||||
.authConfig(AuthConfig.builder()
|
||||
.clientId("a")
|
||||
.clientSecret("a")
|
||||
.redirectUri("https://www.justauth.cn")
|
||||
.alipayPublicKey("asd")
|
||||
.authServerId("asd")
|
||||
.agentId("asd")
|
||||
.domainPrefix("asd")
|
||||
.stackOverflowKey("asd")
|
||||
|
||||
.deviceId("asd")
|
||||
.clientOsType(3)
|
||||
.build())
|
||||
.build();
|
||||
System.out.println(value.getTargetClass());
|
||||
System.out.println(authRequest.authorize(AuthStateUtils.createState()));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
package me.zhyd.oauth.config;
|
||||
|
||||
import me.zhyd.oauth.request.AuthDefaultRequest;
|
||||
import me.zhyd.oauth.request.AuthExtendRequest;
|
||||
|
||||
/**
|
||||
* 测试自定义实现{@link AuthSource}接口后的枚举类
|
||||
*
|
||||
@@ -59,5 +62,11 @@ public enum AuthExtendSource implements AuthSource {
|
||||
public String refresh() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthExtendRequest.class;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ public class GlobalAuthUtilsTest {
|
||||
oauthParams.forEach((k, v) -> oauthParams.put(k, "\"" + GlobalAuthUtils.urlEncode(v) + "\""));
|
||||
|
||||
String actual = "OAuth " + GlobalAuthUtils.parseMapToString(oauthParams, false).replaceAll("&", ", ");
|
||||
assertEquals("OAuth oauth_nonce=\"sTj7Ivg73u052eXstpoS1AWQCynuDEPN\", oauth_signature=\"yHHq2J1W5QLAO8gGipnY1V%2Bzxqk%3D\", oauth_token=\"1961977975-PcFQaCnpN9h9xqtqHwHlpGBXFrHJ9bOLy7OtGAL\", oauth_consumer_key=\"HD0XLqzi5Wz0G08rh45Cg8mgh\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"1569751082\", oauth_version=\"1.0\"", actual);
|
||||
assertEquals("OAuth oauth_nonce=\"sTj7Ivg73u052eXstpoS1AWQCynuDEPN\", oauth_signature=\"OsqHjRmBf7syxlz8lB7MRdzqEjY%3D\", oauth_token=\"1961977975-PcFQaCnpN9h9xqtqHwHlpGBXFrHJ9bOLy7OtGAL\", oauth_consumer_key=\"HD0XLqzi5Wz0G08rh45Cg8mgh\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"1569751082\", oauth_version=\"1.0\"", actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -200,7 +200,7 @@ public class GlobalAuthUtilsTest {
|
||||
queryParams.put("name", "你好");
|
||||
queryParams.put("gender", "male");
|
||||
|
||||
assertEquals("J6MAQH1kcgUdj2jmygN3rdfI4lo=", GlobalAuthUtils.generateTwitterSignature(queryParams, "GET", TWITTER.userInfo(), "xxxxx", "xxxxx"));
|
||||
assertEquals("20FYnV2aZnxNQtp+I0tpMRTvcx0=", GlobalAuthUtils.generateTwitterSignature(queryParams, "GET", TWITTER.userInfo(), "xxxxx", "xxxxx"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user