1
0
mirror of synced 2026-05-22 21:53:18 +00:00

Compare commits

...

41 Commits

Author SHA1 Message Date
yadong.zhang 80132b69e7 💩 修改 AuthSource 中的 [企业微信二维码第三方登录] 2021-08-15 22:57:01 +08:00
yadong.zhang 95158654a9 📝 编写文档 2021-08-15 22:54:29 +08:00
yadong.zhang f2e609192a 🔖 发布 1.16.3 版本 2021-08-15 22:52:58 +08:00
yadong.zhang 8c8f7a27a2 🙈 更新 .gitignore 文件 2021-08-15 22:52:41 +08:00
yadong.zhang 8283124c57 👽 增加 codechina 2021-08-15 22:52:24 +08:00
yadong.zhang 39b113b194 🐛 解决 Line 的 bug。Github Issue (#122) 2021-08-15 22:51:14 +08:00
yadong.zhang e45ef2ec31 🔖 修改 since 编号 2021-08-15 22:49:33 +08:00
yadong.zhang d114368a0d Merge branch 'master' into dev 2021-08-15 22:37:28 +08:00
yadong.zhang 0047cde50e Merge pull request #128 from kang8/dev
[WIP] doc: 添加快照版本对应更详细的文档
2021-08-15 09:33:21 -05:00
yadong.zhang f2c1c0f8a6 Merge pull request #127 from zheng-jx/master
企业微信第三方登录
2021-08-15 09:31:08 -05:00
kang 21e23aadb9 doc: 添加快照版本的文档编写 2021-08-14 23:57:14 +08:00
yadong.zhang db3f7da181 📝 Writing docs. 2021-08-13 18:26:23 +08:00
yadong.zhang 004e5a180f 📝 Writing docs. 2021-08-13 18:06:14 +08:00
yadong.zhang 50c31e5dea Merge pull request #126 from kang8/dev
[WIP] 添加发布快照的 workflow
2021-08-12 06:06:58 -05:00
zheng-jx 7d6049da67 企业微信第三方登录
接入链接https://open.work.weixin.qq.com/api/doc/90001/90143/91123
2021-08-11 15:50:39 +08:00
yadong.zhang 9a24553acd 🐛 预防 NPE 2021-08-11 11:03:08 +08:00
yadong.zhang d75d91db0d 📝 补充文档说明 2021-08-11 10:57:25 +08:00
yadong.zhang e1a4688ac0 📝 修复文案错误 2021-08-11 10:56:04 +08:00
yadong.zhang b1d3790ae1 author 2021-08-11 10:54:43 +08:00
yadong.zhang e5548b0173 🔖 修改版本号为 1.16.3 2021-08-11 10:51:25 +08:00
yadong.zhang ebf39627dd 添加 AuthRequestBuilder 可以便捷的创建 AuthRequest 2021-08-11 10:49:45 +08:00
yadong.zhang 74ee17b242 !27 获取三方实例 部分 进行重构,使之可以进行更简单的获取对应的实例。
Merge pull request !27 from 陈宁/master
2021-08-10 10:06:19 +00:00
ngcly b77de0bd0c 还原 2021-08-10 12:28:56 +08:00
ngcly e55033f4f5 格式化 2021-08-10 10:27:01 +08:00
ngcly 37b7784f89 格式化 2021-08-10 10:24:36 +08:00
ngcly 7cdc719166 继续进行优化,去掉多余的改动 2021-08-10 10:18:42 +08:00
ngcly 5073f82897 1 2021-08-10 00:01:12 +08:00
ngcly 9971793f0c 获取三方实例 部分 进行重构,使之可以进行更简单的获取对应的实例。
如之前获取对应的实例:
        switch (source.toLowerCase()) {
            case "dingtalk":
                authRequest = new AuthDingTalkRequest(AuthConfig.builder()
                        .clientId("")
                        .clientSecret("")
                        .redirectUri("http://localhost:8443/oauth/callback/dingtalk")
                        .build());
                break;
            case "baidu":
                authRequest = new AuthBaiduRequest(AuthConfig.builder()
                        .clientId("")
                        .clientSecret("")
                        .redirectUri("http://localhost:8443/oauth/callback/baidu")
                        .scopes(Arrays.asList(
                                AuthBaiduScope.BASIC.getScope(),
                                AuthBaiduScope.SUPER_MSG.getScope(),
                                AuthBaiduScope.NETDISK.getScope()
                        ))
                        .build());
                break;
               }
上面需要调用端自己去根据source编码进行 new 对应的子类,这是不合理的。调用者应该只需要关心source码和对应的配置。
现在重构后,调用端只需要传入对应的source 和自定义的配置 通过统一的入口就可以拿到正确的实例。不需要调用端做各种判断,所有逻辑判断在服务端这边做好了处理。
调用端代码如下:
        AuthDefaultSource defaultSource = AuthDefaultSource.getAuthSource("wechat_mp");
        AuthRequest request = defaultSource.getAuthRequestInstance(AuthConfig.builder()
            .clientId("a")
            .clientSecret("a")
            .redirectUri("https://www.justauth.cn")
            .build());
2021-08-09 23:48:31 +08:00
kang 9fc3131640 test: 修复 twitter userInfo api 修改后测试同步问题 2021-08-07 11:28:20 +08:00
kang 3f4436bcb6 ci: add upload ossrh snapshotRepository config 2021-08-07 11:12:10 +08:00
kang 0678202baa ci: add deploy snapshot workflow 2021-08-07 11:07:52 +08:00
yadong.zhang af8fda700b 📝 更新文档 2021-07-28 13:36:36 +08:00
yadong.zhang 881a87ed95 📝 修复 twitter 平台无法获取用户邮箱的问题 2021-07-28 09:53:44 +08:00
yadong.zhang 4c8fdbae49 📝 修复“淘宝”平台授权登录后没有uid的问题、增加刷新token的功能 2021-07-06 22:19:30 +08:00
yadong.zhang e8db2dd282 📝 更新文档 2021-06-03 20:53:16 +08:00
yadong.zhang 90374762e4 增加“程序员客栈” 2021-06-03 15:18:51 +08:00
yadong.zhang e5d44e91b8 👽 优化代码 2021-05-14 17:02:12 +08:00
yadong.zhang 41559fc954 📝 更新文档 2021-05-11 12:28:38 +08:00
yadong.zhang d354278e7d 📝 更新文档 2021-05-11 12:27:15 +08:00
yadong.zhang c2d6661a76 !24 update README.md. maxkey update
Merge pull request !24 from MaxKeyTop/N/A
2021-05-11 12:22:30 +08:00
MaxKeyTop 5ee87760be update README.md. maxkey update 2021-05-10 21:03:41 +08:00
27 changed files with 1142 additions and 111 deletions
+44
View File
@@ -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 }}
-2
View File
@@ -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
+29
View File
@@ -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
View File
@@ -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: ![](https://img.shields.io/github/v/release/justauth/JustAuth?style=flat-square)
> - SNAPSHOT: ![](https://img.shields.io/nexus/s/https/oss.sonatype.org/me.zhyd.oauth/JustAuth.svg?style=flat-square)
- Add http dependencyOnly 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
+132 -37
View File
@@ -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** 可选:
> - 稳定版:![](https://img.shields.io/github/v/release/justauth/JustAuth?style=flat-square)
> - 快照版:![](https://img.shields.io/nexus/s/https/oss.sonatype.org/me.zhyd.oauth/JustAuth.svg?style=flat-square)
> > 注意:快照版本是功能的尝鲜,并不保证稳定性。请勿在生产环境中使用。
>
> <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(仅限支付宝))、state1.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)
+1
View File
@@ -0,0 +1 @@
git pull origin dev && git pull github dev && git pull cc dev
+1
View File
@@ -0,0 +1 @@
git push origin dev && git push github dev && git push cc dev
+1
View File
@@ -0,0 +1 @@
git push origin master && git push github master && git push cc master
+1 -1
View File
@@ -1 +1 @@
1.16.1
1.16.3
+3
View File
@@ -15,6 +15,9 @@ case "$1" in
'updv')
bin/updVersion.sh $2
;;
'ppd')
bin/pull-dev.sh
;;
'pd')
bin/push-dev.sh
;;
+10 -5
View File
@@ -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