Compare commits
41 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 |
@@ -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,32 @@
|
||||
## 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
|
||||
|
||||
+77
-21
@@ -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.16.1-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,9 +17,6 @@
|
||||
<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.16.1-orange" ></img>
|
||||
</a>
|
||||
<a target="_blank" href="https://justauth.wiki" title="参考文档">
|
||||
<img src="https://img.shields.io/badge/Docs-latest-blueviolet.svg" ></img>
|
||||
</a>
|
||||
@@ -52,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.16.1</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
|
||||
@@ -110,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
|
||||
|
||||
@@ -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.16.1-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,9 +17,6 @@
|
||||
<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.16.1-orange" ></img>
|
||||
</a>
|
||||
<a target="_blank" href="https://justauth.wiki" title="参考文档">
|
||||
<img src="https://img.shields.io/badge/Docs-latest-blueviolet.svg" ></img>
|
||||
</a>
|
||||
@@ -64,15 +64,85 @@ JustAuth 集成了诸如:Github、Gitee、支付宝、新浪微博、微信、
|
||||
|
||||
## 快速开始
|
||||
|
||||
- 引入依赖
|
||||
### 引入依赖
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>me.zhyd.oauth</groupId>
|
||||
<artifactId>JustAuth</artifactId>
|
||||
<version>1.16.1</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()
|
||||
@@ -87,43 +157,64 @@ 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();
|
||||
```
|
||||
|
||||
## 赞助和支持
|
||||
|
||||
感谢以下赞助商的支持:
|
||||
|
||||
<a href="https://www.duohui.cn?utm_source=justauth" target="_blank"><img src="https://docs.duohui.cn/brand_source/img/std.svg" alt="多会 - 专业活动管理系统" style="height: 54px;" height="54px" /></a>
|
||||
[我要赞助](https://justauth.wiki/sponsor.html)
|
||||
|
||||
## JustAuth 的用户
|
||||
有很多公司、组织和个人把 JustAuth 用于学习、研究、生产环境和商业产品中,包括(但不限于):
|
||||
@@ -133,20 +224,24 @@ authRequest.login(callback);
|
||||
怎么没有我?[登记](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:
|
||||
|
||||
<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.html)
|
||||
- [CHANGELOGS](https://justauth.wiki/update.html)
|
||||
- [PLAN](https://gitee.com/yadong.zhang/JustAuth/issues/IUGRK)
|
||||
|
||||
@@ -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
|
||||
+1
-1
@@ -1 +1 @@
|
||||
1.16.1
|
||||
1.16.3
|
||||
|
||||
@@ -15,6 +15,9 @@ case "$1" in
|
||||
'updv')
|
||||
bin/updVersion.sh $2
|
||||
;;
|
||||
'ppd')
|
||||
bin/pull-dev.sh
|
||||
;;
|
||||
'pd')
|
||||
bin/push-dev.sh
|
||||
;;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>me.zhyd.oauth</groupId>
|
||||
<artifactId>JustAuth</artifactId>
|
||||
<version>1.16.1</version>
|
||||
<version>1.16.3</version>
|
||||
|
||||
<name>JustAuth</name>
|
||||
<url>https://gitee.com/yadong.zhang/JustAuth</url>
|
||||
@@ -157,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>
|
||||
@@ -222,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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -65,6 +65,13 @@ public class AuthConfig {
|
||||
*/
|
||||
private String agentId;
|
||||
|
||||
/**
|
||||
* 企业微信第三方授权用户类型,member|admin
|
||||
*
|
||||
* @since 1.10.0
|
||||
*/
|
||||
private String usertype;
|
||||
|
||||
/**
|
||||
* 域名前缀。
|
||||
* <p>
|
||||
|
||||
@@ -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,6 +82,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String userInfo() {
|
||||
return "https://gitee.com/api/v5/user";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthGiteeRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 钉钉扫码登录
|
||||
@@ -90,6 +106,11 @@ 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;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 钉钉账号登录
|
||||
@@ -109,6 +130,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String userInfo() {
|
||||
return DINGTALK.userInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthDingTalkAccountRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 百度
|
||||
@@ -138,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
|
||||
@@ -157,6 +188,11 @@ 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,
|
||||
@@ -179,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 开源中国
|
||||
@@ -198,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;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 支付宝
|
||||
@@ -217,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
|
||||
@@ -241,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;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 微信开放平台
|
||||
@@ -265,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;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 微信公众平台
|
||||
@@ -289,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;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 淘宝
|
||||
@@ -308,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
|
||||
@@ -327,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
|
||||
@@ -346,6 +422,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String userInfo() {
|
||||
return "https://graph.facebook.com/v10.0/me";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthFacebookRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 抖音
|
||||
@@ -370,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;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 领英
|
||||
@@ -394,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;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 微软
|
||||
@@ -418,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;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 小米
|
||||
@@ -442,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;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 今日头条
|
||||
@@ -461,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
|
||||
@@ -485,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;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -510,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;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -530,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;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -550,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;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -577,6 +703,11 @@ 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;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -599,8 +730,51 @@ 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;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 企业微信网页登录
|
||||
*/
|
||||
@@ -619,6 +793,11 @@ 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 AuthWeChatEnterpriseWebRequest.class;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -646,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;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -668,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;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -695,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;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -724,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;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -744,7 +943,12 @@ 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;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -775,6 +979,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String refresh() {
|
||||
return "https://open.feishu.cn/open-apis/authen/v1/refresh_access_token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthFeishuRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 京东
|
||||
@@ -801,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;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -826,6 +1040,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String refresh() {
|
||||
return "https://oauth.aliyun.com/v1/token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthAliyunRequest.class;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -851,6 +1070,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String refresh() {
|
||||
return "https://oauth.aliyun.com/v1/token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthXmlyRequest.class;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -878,6 +1102,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String refresh() {
|
||||
return "https://api.amazon.com/auth/o2/token";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthAmazonRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Slack
|
||||
@@ -911,6 +1140,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String revoke() {
|
||||
return "https://slack.com/api/auth.revoke";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthSlackRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* line
|
||||
@@ -942,6 +1176,11 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
public String revoke() {
|
||||
return "https://api.line.me/oauth2/v2.1/revoke";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends AuthDefaultRequest> getTargetClass() {
|
||||
return AuthLineRequest.class;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Okta,
|
||||
@@ -975,5 +1214,37 @@ public enum AuthDefaultSource implements AuthSource {
|
||||
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,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;
|
||||
|
||||
}
|
||||
@@ -35,7 +35,7 @@ public abstract class AbstractAuthWeChatEnterpriseRequest extends AuthDefaultReq
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
String response = doGetAuthorizationCode(accessTokenUrl(authCallback.getCode()));
|
||||
String response = doGetAuthorizationCode(accessTokenUrl(null));
|
||||
|
||||
JSONObject object = this.checkResponse(response);
|
||||
|
||||
|
||||
@@ -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,15 @@ 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) {
|
||||
@@ -54,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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -37,7 +37,22 @@ public class AuthLineRequest extends AuthDefaultRequest {
|
||||
|
||||
@Override
|
||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||
return this.getToken(accessTokenUrl(authCallback.getCode()));
|
||||
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
|
||||
@@ -74,28 +89,23 @@ public class AuthLineRequest extends AuthDefaultRequest {
|
||||
|
||||
@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(this.getToken(refreshTokenUrl(oldToken.getRefreshToken())))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取token,适用于获取access_token和刷新token
|
||||
*
|
||||
* @param accessTokenUrl 实际请求token的地址
|
||||
* @return token对象
|
||||
*/
|
||||
private AuthToken getToken(String accessTokenUrl) {
|
||||
String response = new HttpUtils(config.getHttpConfig()).post(accessTokenUrl);
|
||||
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"))
|
||||
.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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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}
|
||||
*
|
||||
|
||||
@@ -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();
|
||||
@@ -119,17 +119,15 @@ public class AuthTwitterRequest extends AuthDefaultRequest {
|
||||
@Override
|
||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||
Map<String, String> queryParams = new HashMap<>(5);
|
||||
queryParams.put("user_id", authToken.getUserId());
|
||||
queryParams.put("screen_name", authToken.getScreenName());
|
||||
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,9 +154,8 @@ 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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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,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