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

Compare commits

..

175 Commits

Author SHA1 Message Date
yadong.zhang 6b758e0e1e 💡 修改注释 2023-12-03 21:50:50 +08:00
yadong.zhang 02bd057963 🔀 合并 PR#166 2023-12-03 21:05:53 +08:00
yadong.zhang 4d2a110fea Merge pull request #166 from christxlx/master
fix: bug 58-63 scope在微软最新的文档中要求必须用空格隔开,form构建时候空格会被强制转换为%20,所以此处重新覆盖
2023-12-03 21:04:10 +08:00
yadong.zhang 2ef8298278 Merge branch 'master' into dev 2023-12-03 21:01:16 +08:00
yadong.zhang 80ce57bce4 📝 编写文档 2023-12-03 21:00:45 +08:00
yadong.zhang 2fed3e5ba2 💩 修改 facebook 平台的 scope 2023-12-03 20:58:49 +08:00
yadong.zhang 1d38ce2835 💩 微软平台适配 AzureAD(目前改名为 Microsoft Entra ID)登录认证 2023-12-03 20:18:39 +08:00
yadong.zhang 14dd2b6179 💩 修复微信公众平台 scope 为 snsapi_base 登录报错的问题 [181](https://github.com/justauth/JustAuth/issues/181) 2023-12-03 20:17:47 +08:00
yadong.zhang d6ba3bba10 💩 修复 twitter 平台在 Java11 环境下登录失败的问题。[#174](https://github.com/justauth/JustAuth/issues/174) 2023-12-03 16:55:55 +08:00
yadong.zhang fe328c7375 💩 调整单元测试 2023-08-06 18:17:53 +08:00
yadong.zhang 102521a979 Merge branch 'dev' 2023-08-06 18:15:11 +08:00
yadong.zhang 924f0f552b 🔥 更新脚本 2023-08-06 18:14:42 +08:00
yadong.zhang 7167a74af2 💩 调整单元测试 2023-08-06 18:14:04 +08:00
yadong.zhang c0ac81df08 Merge remote-tracking branch 'origin/master' 2023-08-06 18:10:09 +08:00
yadong.zhang 56cdd20600 Merge branch 'master' of gitee.com:yadong.zhang/JustAuth into dev 2023-08-06 18:07:45 +08:00
yadong.zhang 87d8c1d164 Merge branch 'master' into dev 2023-08-06 17:58:24 +08:00
yadong.zhang d1f820514f ⬆️ 1.16.6 2023-08-06 17:57:47 +08:00
yadong.zhang 6d192e94ac Merge branch 'dev' of gitee.com:yadong.zhang/JustAuth into dev 2023-08-06 17:50:07 +08:00
yadong.zhang 02bec576de Merge branch 'dev'
# Conflicts:
#	README.md
2023-04-11 22:48:07 +08:00
yadong.zhang 0d599d75f0 替换 justauth.wiki 域名,该域名暂时不可用,请使用 justauth.cn 2023-04-11 22:46:53 +08:00
yadong.zhang 5171fb8148 替换 justauth.wiki 域名,该域名暂时不可用,请使用 justauth.cn 2023-04-11 22:45:58 +08:00
yadong.zhang 0025748ba7 替换 justauth.wiki 域名,该域名暂时不可用,请使用 justauth.cn 2023-04-11 22:42:47 +08:00
yadong.zhang 87cf45b675 替换 justauth.wiki 域名,该域名暂时不可用,请使用 justauth.cn 2023-04-11 22:41:18 +08:00
yadong.zhang bd1192f17f Merge branch 'dev'
# Conflicts:
#	README.md
2023-04-11 22:39:57 +08:00
yadong.zhang a7cb4aefc0 替换 justauth.wiki 域名,该域名暂时不可用,请使用 justauth.cn 2023-04-11 22:38:04 +08:00
yadong.zhang 7ffda8737c 替换 justauth.wiki 域名,该域名暂时不可用,请使用 justauth.cn 2023-04-11 22:34:18 +08:00
yadong.zhang 90a9d56fd0 替换 justauth.wiki 域名,该域名暂时不可用
Signed-off-by: yadong.zhang <yadong.zhang0415@gmail.com>
2023-04-11 14:25:54 +00:00
yadong.zhang c53c763540 !36 新增afdian授权示例图
Merge pull request !36 from ヽ米 饭/handy
2023-03-25 09:41:31 +00:00
韩帅 dc18304eee feat: 新增afdian授权示例图 2023-03-24 16:50:37 +08:00
yadong.zhang a558379680 !35 新增爱发电平台
Merge pull request !35 from ヽ米 饭/handy
2023-03-21 10:55:56 +00:00
韩帅 142846b2fa 新增爱发电平台 2023-03-21 17:42:46 +08:00
Christ 80b59fc13c fix: bug 58-63 scope在微软最新的文档中要求必须用空格隔开,form构建时候空格会被强制转换为%20,所以此处重新覆盖 2023-03-21 14:41:30 +08:00
yadong.zhang 765127e847 📝 更新文档 2023-02-26 18:09:08 +08:00
yadong.zhang 11707e6903 🔥 微信公众平台支持返回快照数据 2023-02-26 17:54:58 +08:00
yadong.zhang 3564c846f4 Merge branch 'master' of gitee.com:yadong.zhang/JustAuth into dev 2023-02-26 16:47:46 +08:00
yadong.zhang 0bc4c806bf ⬆️ Merge branch 'dev' 2023-02-26 16:47:27 +08:00
yadong.zhang 35c754f327 Merge branch 'master' of gitee.com:yadong.zhang/JustAuth 2023-02-26 16:32:19 +08:00
yadong.zhang 45ebe26f1b ⬆️ Merge branch 'dev' 2023-02-26 16:32:16 +08:00
yadong.zhang 30f4a29f48 Merge branch 'dev' of gitee.com:yadong.zhang/JustAuth 2023-02-26 16:27:49 +08:00
yadong.zhang ca8e194c4e Merge pull request #159 from cheng521521/master
添加飞书单元测试
2023-02-26 16:19:58 +08:00
yadong.zhang 81ea4b1620 Merge pull request #155 from marquis-chen/dev
企业微信网页登录--获取用户敏感信息
2023-02-26 16:19:28 +08:00
yadong.zhang cc74d4a5c8 !33 【轻量级 PR】:update pom.xml.
Merge pull request !33 from test/N/A
2023-02-24 12:15:56 +00:00
test e80304601f update pom.xml.
升级fastjson版本到1.2.83,1.2.83版本之前存在代码执行漏洞风险 ,CVE-2022-25845	

Signed-off-by: test <531648642@qq.com>
2023-02-24 11:54:47 +00:00
yadong.zhang afddf269e1 !31 修复企业微信的 redirect_uri 没有 urlEncode 问题
Merge pull request !31 from AlexChan/dev
2022-10-23 12:06:06 +00:00
alexchan bac494a7fc 修复企业微信的 redirect_uri 没有 urlEncode 问题 2022-10-21 16:22:13 +08:00
chengpengxiang 7a9d602499 test:添加飞书单元测试 2022-10-03 13:17:28 +08:00
marquis chen f3a8cf675c 企业微信网页登录增加AgentId参数,对重定向地址UrlEncode,获取用户敏感信息 2022-09-05 16:42:51 +08:00
yadong.zhang 571466f079 Merge pull request #149 from justauth/dependabot/maven/com.alibaba-fastjson-1.2.83
⬆️ Bump fastjson from 1.2.78 to 1.2.83
2022-08-07 22:59:14 +08:00
dependabot[bot] e1b912bdf6 ⬆️ Bump fastjson from 1.2.78 to 1.2.83
Bumps [fastjson](https://github.com/alibaba/fastjson) from 1.2.78 to 1.2.83.
- [Release notes](https://github.com/alibaba/fastjson/releases)
- [Commits](https://github.com/alibaba/fastjson/compare/1.2.78...1.2.83)

---
updated-dependencies:
- dependency-name: com.alibaba:fastjson
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-17 02:05:50 +00:00
yadong.zhang 02674049d0 📝 更新说明 2021-10-18 10:03:14 +08:00
yadong.zhang f1714726f5 Merge branch 'carldea/master' into dev 2021-10-18 09:55:40 +08:00
yadong.zhang a3108caccf 🐛 修复 alipay 登录失败的 BUG 2021-10-16 19:11:24 +08:00
yadong.zhang e134dd06b0 ⬆️ 升级alipay-sdk-version的依赖版本 2021-10-16 19:10:50 +08:00
yadong.zhang 172ba7be55 💩 修改用户logo的尺寸 2021-10-16 19:10:24 +08:00
Carl Dea f9e3053ecc Using TCK Tested JDK builds of OpenJDK
The AdoptOpenJDK has been discontinued since July 2021. When using Zulu you get all the latest updated (TCK Tested) builds for all versions of OpenJDK included archived major fixed versions.
2021-09-27 14:37:10 -04:00
Carl Dea 99c9ba2854 Using TCK Tested JDK builds of OpenJDK
The AdoptOpenJDK has been discontinued since July 2021. When using Zulu you get all the latest updated (TCK Tested) builds for all versions of OpenJDK included archived major fixed versions.
2021-09-27 14:36:33 -04:00
yadong.zhang 544ffd5372 💩 修复s一样的代码 2021-09-22 17:47:12 +08:00
yadong.zhang 522ebbfa7f 📝 编写文档 2021-09-22 17:16:43 +08:00
yadong.zhang 497498dbf4 Merge pull request #134 from verils/remove-provider-specific-properties
把Alipay独有的配置从AuthConfig里提取出来
2021-09-20 07:51:16 -05:00
yadong.zhang 62cd7af619 Merge pull request #133 from kang8/test
refactor: 重构 workflow
2021-09-20 07:43:28 -05:00
yadong.zhang 3a3f69692c 📝 编写文档 2021-09-20 20:39:49 +08:00
yadong.zhang c87015e34f 📝 编写文档 2021-09-20 20:37:24 +08:00
yadong.zhang 96773dd92d ⬆️ 升级第三方的依赖 2021-09-20 20:37:10 +08:00
yadong.zhang 644ef02264 ⬆️ 升级 simple-http 到 1.0.5 2021-09-18 00:35:42 +08:00
verils 4c205a9957 把第三方服务独有的配置从AuthConfig里提取出来 2021-09-01 12:42:41 +08:00
kang ea70c5fc81 ci: 快照版本切换,使用 python 脚本替换 maven 插件 2021-08-27 08:12:41 +08:00
kang 9ced525309 refactor: 重构流水线构建 2021-08-27 08:05:24 +08:00
yadong.zhang 2de0ad5013 !28 添加微软中国(世纪互联)第三方登录,新增微软方式登录的redirectUri校验
Merge pull request !28 from mroldx/dev
2021-08-26 12:06:43 +00:00
974751082@qq.com 23b7bcf43d 添加微软中国(世纪华联)第三方登录,新增微软方式登录的redirectUri校验 2021-08-25 23:06:29 +08:00
yadong.zhang 976b7d8b2b Create FUNDING.yml 2021-08-16 12:09:01 +08:00
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
yadong.zhang 94f6540338 📝 更新文档 2021-04-19 21:00:19 +08:00
yadong.zhang 7bc7a92efb 📝 更新文档 2021-04-19 14:05:22 +08:00
yadong.zhang b5920872d5 Merge branch 'master' of github.com:justauth/JustAuth into dev 2021-04-19 14:03:25 +08:00
yadong.zhang 0bdf881849 Merge pull request #115 from leewenlong/patch-1
修正若干注释
2021-04-15 09:40:23 +08:00
yadong.zhang 46f7c72744 📝 更新文档 2021-04-12 11:41:43 +08:00
leewenlong 4a662ba5cd Update AuthCodingRequest.java
修正注释
2021-04-10 18:02:33 +08:00
leewenlong 040587d5b2 Update AuthGithubScope.java
修正注释
2021-04-10 18:01:29 +08:00
leewenlong c81411fd39 Update AuthBaiduScope.java
改正注释
2021-04-10 17:55:05 +08:00
yadong.zhang 0e1b000bd8 ⬆️ 升级 fastjsonv1.2.76 2021-04-09 08:44:53 +08:00
yadong.zhang f9b30c735b 🔖 Update version to 1.16.1 2021-04-09 08:40:10 +08:00
yadong.zhang 0f42457d91 🐛 解决企业微信授权后,回调地址中原有的参数丢失的问题 2021-04-09 08:35:26 +08:00
yadong.zhang fa75568996 抖音平台支持自定义 scope 2021-04-09 08:34:14 +08:00
yadong.zhang f44ceeeeeb 增加忽略校验 redirectUri 的配置 2021-04-09 08:33:21 +08:00
yadong.zhang ec4c009ed8 📝 更新文档 2021-04-08 09:43:34 +08:00
yadong.zhang 03fbbe0d3a 📝 更新文档 2021-04-07 20:52:04 +08:00
yadong.zhang e64e9def63 📝 更新文档 2021-04-07 20:14:01 +08:00
yadong.zhang 25f99f7560 📝 更新文档 2021-04-07 20:12:22 +08:00
yadong.zhang 0433f54564 📝 更新文档 2021-04-07 19:26:07 +08:00
yadong.zhang 423d9f45b6 📝 更新文档 2021-04-07 19:25:23 +08:00
yadong.zhang 7a9e6214de 👽 集成 Okta 2021-03-30 23:26:56 +08:00
yadong.zhang 3753e3b9bc 👽 AuthConfig 中 CodingGroupName 改为 DomainPrefix 2021-03-30 23:25:30 +08:00
yadong.zhang bc3af96328 👽 优化代码 2021-03-30 23:22:05 +08:00
yadong.zhang b700902c04 📝 更新文档 2021-03-29 11:03:37 +08:00
yadong.zhang 2d0ae7cc27 📝 文档 2021-03-29 11:00:56 +08:00
yadong.zhang 3e4faa75fe 📝 更新脚本 2021-03-29 10:45:07 +08:00
yadong.zhang 6a36ad6af2 📝 更新文档 2021-03-29 10:44:44 +08:00
yadong.zhang 13514d6a92 调整 map 声明时的初始容量 2021-03-29 10:44:28 +08:00
yadong.zhang 6a479d9c1d 🥚 集成 Slack 和 Line 2021-03-29 10:43:47 +08:00
yadong.zhang 2e64fb9693 🥚 集成 Slack 2021-03-29 10:43:15 +08:00
yadong.zhang 0e8308e6c9 🥚 集成 Line 2021-03-29 10:42:57 +08:00
yadong.zhang 3933b3b7ee 🥚 增加钉钉账号登录 2021-03-19 14:37:37 +08:00
yadong.zhang a99b818810 update CHANGELOGS.md. 2021-03-16 17:29:55 +08:00
yadong.zhang cd324cc7c1 🔖 Release version 1.16.0 2021-03-13 23:15:22 +08:00
yadong.zhang 3e890f2c2a 📌 升级 FaceBook API 版本到 v10.0 2021-03-13 23:14:26 +08:00
yadong.zhang ba56f5ab5a 🔧 facebook scope 增加默认值 2021-03-13 23:11:32 +08:00
yadong.zhang 132a7f4338 🥚 添加 amazon 平台 2021-03-13 23:10:48 +08:00
yadong.zhang c79b97a0d0 !22 jdk8 maven打包编译报错: src\main\java\me\zhyd\oauth\config\JustAuthLogConfig.java:8: 错误: 未知标记: date
Merge pull request !22 from xhal/master
2021-03-04 08:47:26 +08:00
xhal 66df3ac027 update pom.xml - 1.8 javadoc 配置 2021-03-03 17:46:16 +08:00
xhal 11df93ad44 update pom.xml. 2021-03-03 17:06:08 +08:00
yadong.zhang e3f5f49ec8 💡 更新帮助文档链接 2021-02-19 17:58:39 +08:00
yadong.zhang 23eb2cfcc8 💡 修改文档 2021-02-19 17:52:29 +08:00
yadong.zhang 30461e62f9 💡 修改文档 2021-02-19 17:51:14 +08:00
yadong.zhang dfbbd9ae0d 💡 修改文档 2021-02-19 17:46:11 +08:00
yadong.zhang 05b7746f26 💡 修改文档 2021-02-19 17:37:23 +08:00
yadong.zhang 21422b02aa Merge pull request #110 from hangsman/master
feat: 增加全局日志配置类
2021-01-15 18:33:28 +08:00
HeJin 10e445e87c feat: 增加全局日志配置类 2021-01-09 20:38:33 +08:00
yadong.zhang d6cbcecaab 💡 修改注释、文档 2021-01-04 15:19:19 +08:00
yadong.zhang 050459e616 📝 Writing docs. 2021-01-01 18:28:43 +08:00
yadong.zhang 9fd2b9b919 🥚 正式启用飞书登录 2021-01-01 17:48:49 +08:00
yadong.zhang 2ff5570399 💡 更新注释 2021-01-01 15:22:30 +08:00
yadong.zhang 1bec384525 👽 重命名企业微信扫码登录 request 类名,补充文档说明 2021-01-01 15:20:57 +08:00
yadong.zhang 824c68356d 📌 升级 FaceBook API 版本到 v9.0 2021-01-01 10:40:18 +08:00
yadong.zhang f5e3c225f6 📝 Writing docs. 2021-01-01 10:27:52 +08:00
yadong.zhang 0259669288 Merge branch 'dev' of github.com:justauth/JustAuth into dev 2021-01-01 10:10:20 +08:00
yadong.zhang edc9d1a3c3 Merge pull request #107 from 937624219/dev
添加AuthAlipayRequest网络代理构造器
2021-01-01 10:03:30 +08:00
yadong.zhang d886bc95a2 Merge pull request #105 from jianghuzai/WeChatEnterpriseWeb
支持企业微信网页授权登录
2021-01-01 09:56:40 +08:00
冬瓜 7aaf52e953 添加AuthAlipayRequest网络代理构造器 2020-12-27 11:08:57 +08:00
yadong.zhang e84bd7cdb5 🔖 merge #101 2020-12-20 17:14:06 +08:00
guanhua.li 28e19960f2 支持企业微信网页授权登录 2020-12-16 10:02:37 +08:00
yadong.zhang dce2bd1e1e Merge pull request #101 from zwzch/dev
支持喜马拉雅登录
2020-12-09 13:18:52 +08:00
zwzch bc30971482 优化代码
Signed-off-by: zwzch <zwzch4j@gmail.com>
2020-11-06 20:14:52 +08:00
zwzch 9bd6d88049 喜马拉雅登录
Signed-off-by: zwzch <zwzch4j@gmail.com>
2020-11-06 17:41:28 +08:00
yadong.zhang 442332be57 📝 Writing docs. 2020-11-02 21:30:23 +08:00
yadong.zhang d4bfa8e75f 🔖 sponsors 2020-11-02 21:22:35 +08:00
118 changed files with 3949 additions and 741 deletions
+12
View File
@@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: ['https://www.justauth.cn/sponsor.html']
+2 -2
View File
@@ -9,8 +9,8 @@ assignees: ''
## Pre-submission checklist:
- [ ] I have searched the relevant information in the existing list of Issues.
- [ ] I have searched the developer documentation for that information: https://justauth.wiki
- [ ] I have read the relevant Q&A: https://justauth.wiki/#/Q&A
- [ ] I have searched the developer documentation for that information: https://www.justauth.cn
- [ ] I have read the relevant Q&A: https://www.justauth.cn
## Issue description
+65
View File
@@ -0,0 +1,65 @@
name: Deploy
on:
push:
branches: [ dev ]
paths:
- src/**
- pom.xml
jobs:
test:
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: 'zulu'
- name: Cache m2 package
uses: actions/cache@v2
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- run: mvn test
deploy-snapshot:
needs: test
if: ${{ success() }}
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: 'zulu'
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: setting snapshot version
run: |
import xml.etree.ElementTree as ET
tree = ET.parse("pom.xml")
version = tree.find("{http://maven.apache.org/POM/4.0.0}version")
print(version.text + "-SNAPSHOT")
if version.text.endswith("-SNAPSHOT") == False:
tree.find("{http://maven.apache.org/POM/4.0.0}version").text = version.text + "-SNAPSHOT"
ET.register_namespace("", "http://maven.apache.org/POM/4.0.0")
tree.write("pom.xml", "utf-8", True)
shell: python
- name: deploy snapshot to ossrh repository
run: mvn -B deploy -P snapshot -DskipTests
env:
MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
+26
View File
@@ -0,0 +1,26 @@
name: test pull_request
on:
pull_request:
paths:
- src/**
- pom.xml
jobs:
test:
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: 'zulu'
- name: Cache m2 package
uses: actions/cache@v2
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- run: mvn test
-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
+142 -6
View File
@@ -1,3 +1,139 @@
## 1.16.6
### 2023/12/03
- 优化
- 微信公众平台支持返回快照标识(快照标识为 true 时,标识当前获取到的微信用户信息都是虚拟的)
- 企业微信网页登录--获取用户敏感信。 [Github #155](https://github.com/justauth/JustAuth/pull/155)
- 添加飞书单元测试。 [Github #159](https://github.com/justauth/JustAuth/pull/159)
- 升级fastjson版本到1.2.831.2.83版本之前存在代码执行漏洞风险 CVE-2022-25845。[Gitee PR #31](https://gitee.com/yadong.zhang/JustAuth/pulls/31)
- 新增
- 添加微软中国(世纪华联)第三方登录,新增微软方式登录的redirectUri校验。[Gitee PR #33](https://gitee.com/yadong.zhang/JustAuth/pulls/33)
- 新增爱发电平台 [Gitee #35](https://gitee.com/yadong.zhang/JustAuth/pulls/35)
- 微软平台适配 AzureAD(目前改名为 Microsoft Entra ID)登录认证
- Fixed
- 修复 twitter 平台在 Java11 环境下登录失败的问题。[#174](https://github.com/justauth/JustAuth/issues/174)
- 修复 Facebook 平台无法登录的问题(facebook 平台 API 进行了升级)
- 修复微信公众平台 scope 为 snsapi_base 登录报错的问题 [181](https://github.com/justauth/JustAuth/issues/181)
## 1.16.5
### 2021/10/18
- 合并 PR [Github #138](https://github.com/justauth/JustAuth/pull/138)
- 升级alipay-sdk-version的依赖版本
- 修改用户logo的尺寸
- 修复 alipay 登录失败的 BUG [Gitee Issue #I4E4ML](https://gitee.com/yadong.zhang/JustAuth/issues/I4E4ML)
## 1.16.4
### 2021/9/22
- 合并 PR
- [Github #134](https://github.com/justauth/JustAuth/pull/134)
- [Github #133](https://github.com/justauth/JustAuth/pull/133)
- [Github #132](https://github.com/justauth/JustAuth/pull/132)
- [Github #131](https://github.com/justauth/JustAuth/pull/131)
- 添加微软中国(世纪华联)第三方登录,新增微软方式登录的redirectUri校验。[Gitee PR #28](https://gitee.com/yadong.zhang/JustAuth/pulls/28)
- 升级第三方的依赖
- simple-http > 1.0.5
- lombok > 1.18.20
- junit > 4.13.2
- fastjson > 1.2.78
- alipay-sdk > 4.16.38.ALL
## 1.16.3
### 2021/8/15
- 发布 v1.16.3
- 新增
- 集成“企业微信的第三方应用”平台登录
- PR
- `AuthRequst` 增加 `Builder` 构建方式,使用起来更简单。 ([#27](https://gitee.com/yadong.zhang/JustAuth/pulls/27))
- 使用 Github Action 添加发布快照的 workflow。 ([#126](https://github.com/justauth/JustAuth/pull/126))
- 新增了企业微信的第三方应用登录,`AuthWeChatEnterpriseThirdQrcodeRequest`。 ([#127](https://github.com/justauth/JustAuth/pull/127))
- 添加快照版本对应更详细的文档。 ([#128](https://github.com/justauth/JustAuth/pull/128))
- 修改
- 在 Gitee PR ([#27](https://gitee.com/yadong.zhang/JustAuth/pulls/27)) 的基础上重构代码,增加 Builder 方式创建 AuthRequest
- 解决 Line 登录的错误。[#122](https://github.com/justauth/JustAuth/issues/122)
## 1.16.2
### 2021/7/28
- 发布 v1.16.2
- 新增
- 集成“程序员客栈”平台登录
- 修改
- 更新文档
- 修复“淘宝”平台授权登录后没有`uid`的问题、增加刷新token的功能
- 修复“Twitter”平台授权登录后获取不到用户邮箱的问题
## 1.16.1
### 2021/4/19
- 发布 v1.16.1
- Fix Github issue [#114](https://github.com/justauth/JustAuth/issues/114): 解决企业微信授权后,回调地址中原有的参数丢失的问题
- Fix Github issue [#82](https://github.com/justauth/JustAuth/issues/82): 抖音平台支持自定义 scope
- Fix Github issue [#92](https://github.com/justauth/JustAuth/issues/92): 增加忽略校验 redirectUri 的配置
- Merge Github PR [#115](https://github.com/justauth/JustAuth/pull/115)
- 升级 `fastjson``v1.2.76`
## 1.16.0
### 2021/4/7
- 发布 v1.16.0
- 新增
- 集成 Amazon 平台登录
- 集成 Slack 平台登录
- 集成 LINE 平台登录
- 集成 Okta 平台登录
- 集成钉钉账号登录
- 修改
- 【**重要**】 `AuthConfig`中的`codingGroupName`参数更名为`domainPrefix`,针对此类平台提供通用的配置。
- 修改 `AuthFacebookScope` 中的默认 scope,解决 justauth-demo 项目中使用 facebook 报错的问题
- 升级 facebook 的 api 到 v10.0 版本
- 优化部分代码
- 优化 Map 声明时的初始容量,避免频繁扩容
- 更新 README 文档
- PR
- 合并 [Github #110](https://github.com/justauth/JustAuth/pull/110)
- 合并 [Gitee #22](https://gitee.com/yadong.zhang/JustAuth/pulls/22)
## 1.15.9
### 2021/1/1
- 发布 v1.15.9
- 新增
- 修复并正式启用 飞书 平台的第三方登录
- AuthToken 类中新增 `refreshTokenExpireIn` 记录 refresh token 的有效期
- PR
- 合并 [Github #101](https://github.com/justauth/JustAuth/pull/101) :支持喜马拉雅登录
- 合并 [Github #105](https://github.com/justauth/JustAuth/pull/105) :支持企业微信网页授权登录
- 合并 [Github #107](https://github.com/justauth/JustAuth/pull/107) :添加AuthAlipayRequest网络代理构造器,解决 Github Issue [#102](https://github.com/justauth/JustAuth/issues/102)
- 修改
- 修改喜马拉雅配置参数,将`ClientOsType`参数提到 AuthConfig 中
- AuthChecker 中增加对喜马拉雅平台的校验
- 升级 facebook api 版本到 v9.0,解决 Gitee Issue [#I2AR5S](https://gitee.com/yadong.zhang/JustAuth/issues/I2AR5S)
- !!!**注意**!!!修改原来的企业微信 Request 类名为 `AuthWeChatEnterpriseQrcodeRequest`,升级后注意该点
注意:可能有些开发者对于 JA 集成的四个微信平台不太理解,这儿统一说明:
- 按照类名
- AuthWeChatEnterpriseQrcodeRequest:企业微信二维码登录
- AuthWeChatEnterpriseWebRequest:企业微信网页登录
- AuthWeChatOpenRequest:微信开放平台
- AuthWeChatMpRequest:微信公众平台
- 按照枚举
- WECHAT_ENTERPRISE:企业微信二维码登录
- WECHAT_ENTERPRISE_WEB:企业微信网页登录
- WECHAT_OPEN:微信开放平台
- WECHAT_MP:微信公众平台
## 1.15.8
### 2020/10/25
@@ -42,7 +178,7 @@
- 新增 [微信企业版登录](oauth/wechatEnterprise.md)文档
- 新增 [Facebook 登录](oauth/facebook.md)文档
- 完善 [JustAuth 使用者](users.md)文档
- 替换“帮助文档”域名,由[https://docs.justauth.whnb.wang](https://docs.justauth.whnb.wang)迁移到[https://justauth.wiki](https://justauth.wiki)
- 替换“帮助文档”域名,由[https://docs.justauth.whnb.wang](https://docs.justauth.whnb.wang)迁移到[https://www.justauth.cn](https://www.justauth.cn)
- 新增
- 增加阿里云授权登录中刷新授权token的接口,by “QQ群用户需求”
- AuthConfig 增加忽略校验 state 的参数,详情参考:[Github#Issue#83](https://github.com/justauth/JustAuth/issues/83)
@@ -95,7 +231,7 @@ new AuthGoogleRequest(AuthConfig.builder()
- 修复
- 解决 Twitter 授权失败的BUG
- 文档
- 完善 [https://justauth.wiki](https://justauth.wiki/) 的404引导页内容
- 完善 [https://www.justauth.cn](https://www.justauth.cn/) 的404引导页内容
- 增加名词解释: `uuid`
- 补充 [Q&A](Q&A.md)
- 新增 [参考文档](references.md),包含 OAuth 授权和第三方平台的API文档等内容
@@ -175,9 +311,9 @@ System.setProperty("proxyHost", "127.0.0.1");
- 新增
- 增加微信、QQ、支付宝、微博授权登录的帮助文档
- 合并[PR#57](https://github.com/justauth/JustAuth/pull/57),增加微信公众号登录 by [@xkcoding](https://github.com/xkcoding)
- [帮助文档](https://justauth.wiki)中增加自定义的404页面
- [帮助文档](https://justauth.wiki)中增加Gittalk插件
- [帮助文档](https://justauth.wiki)中增加Java代码高亮的插件
- [帮助文档](https://www.justauth.cn)中增加自定义的404页面
- [帮助文档](https://www.justauth.cn)中增加Gittalk插件
- [帮助文档](https://www.justauth.cn)中增加Java代码高亮的插件
- 增加`AuthUserGender#getWechatRealGender`方法,兼容获取微信平台的用户性别
- 修改
- 修复抖音登录取值取错层级的问题([issue#I15SIG@Gitee](https://gitee.com/yadong.zhang/JustAuth/issues/I15SIG)
@@ -186,7 +322,7 @@ System.setProperty("proxyHost", "127.0.0.1");
- `AuthResponseStatus`枚举类中增加`ILLEGAL_STATUS`、`REQUIRED_REFRESH_TOKEN`两个枚举值
- `AuthSource`接口中增加`getName`方法,用来对外提供实际`source`的字符串值
- `AuthWeiboRequest`微博授权登录中实现`revoke`方法,支持手动回收授权
- [帮助文档](https://justauth.wiki)中修复[腾讯云登录]链接错误的问题
- [帮助文档](https://www.justauth.cn)中修复[腾讯云登录]链接错误的问题
- 升级
- 升级相关依赖:lombok@v1.18.10hutool@5.0.5fastjson@1.2.62alipay@4.8.10.ALL[PR#11@Gitee](https://gitee.com/yadong.zhang/JustAuth/pulls/11)
+89 -71
View File
@@ -1,12 +1,15 @@
<p align="center">
<a href="https://justauth.wiki"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/Justauth.png" width="400"></a>
<a href="https://www.justauth.cn"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/Justauth.png" width="400"></a>
</p>
<p align="center">
<strong>Login, so easy.</strong>
</p>
<p align="center">
<a target="_blank" href="https://search.maven.org/search?q=JustAuth">
<img src="https://img.shields.io/badge/Maven%20Central-1.15.8-blue" ></img>
<img src="https://img.shields.io/github/v/release/justauth/JustAuth?style=flat-square" ></img>
</a>
<a target="_blank" href="https://oss.sonatype.org/content/repositories/snapshots/me/zhyd/oauth/JustAuth/">
<img src="https://img.shields.io/nexus/s/https/oss.sonatype.org/me.zhyd.oauth/JustAuth.svg?style=flat-square" ></img>
</a>
<a target="_blank" href="https://gitee.com/yadong.zhang/JustAuth/blob/master/LICENSE">
<img src="https://img.shields.io/apm/l/vim-mode.svg?color=yellow" ></img>
@@ -14,65 +17,24 @@
<a target="_blank" href="https://www.oracle.com/technetwork/java/javase/downloads/index.html">
<img src="https://img.shields.io/badge/JDK-1.8+-green.svg" ></img>
</a>
<a target="_blank" href="https://apidoc.gitee.com/yadong.zhang/JustAuth/" title="API文档">
<img src="https://img.shields.io/badge/Api%20Docs-1.15.8-orange" ></img>
</a>
<a target="_blank" href="https://justauth.wiki" title="参考文档">
<a target="_blank" href="https://www.justauth.cn" title="参考文档">
<img src="https://img.shields.io/badge/Docs-latest-blueviolet.svg" ></img>
</a>
<a href="https://codecov.io/gh/zhangyd-c/JustAuth">
<img src="https://codecov.io/gh/zhangyd-c/JustAuth/branch/master/graph/badge.svg" />
<a href="https://codecov.io/gh/justauth/JustAuth">
<img src="https://codecov.io/gh/justauth/JustAuth/branch/master/graph/badge.svg?token=zYiAqd9aFz" />
</a>
<a href='https://gitee.com/yadong.zhang/JustAuth/stargazers'>
<img src='https://gitee.com/yadong.zhang/JustAuth/badge/star.svg?theme=white' alt='star'></img>
<img src='https://gitee.com/yadong.zhang/JustAuth/badge/star.svg?theme=gvp' alt='star'></img>
</a>
<a target="_blank" href='https://github.com/zhangyd-c/JustAuth'>
<img src="https://img.shields.io/github/stars/zhangyd-c/JustAuth.svg?style=social" alt="github star"></img>
</a>
</p>
<center>
<table>
<tr>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/gitee.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/github.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/weibo.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/dingtalk.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/baidu.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/coding.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/tencentCloud.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/oschina.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/alipay.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/qq.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/wechat.png" width="20" title="微信开放平台"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/taobao.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/google.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/facebook.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/douyin.png" width="20"></td>
</tr>
</table>
<table>
<tr>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/linkedin.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/microsoft.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/mi.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/toutiao.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/teambition.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/renren.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/pinterest.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/stackoverflow.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/huawei.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/wechat.png" width="20" title="微信企业版"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/csdn.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/kujiale.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/gitlab.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/meituan.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/eleme.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/twitter.png" width="20"></td>
</tr>
</table>
<center><a href="https://justauth.wiki/#/?id=%E5%B7%B2%E9%9B%86%E6%88%90%E7%9A%84%E5%B9%B3%E5%8F%B0" target="_blank">查看更多</a></center>
</center>
-------------------------------------------------------------------------------
<p align="center">
<img src='./docs/media/75a3c076.png' alt='star'></img>
</p>
-------------------------------------------------------------------------------
@@ -81,7 +43,7 @@
`JustAuth`, as you see, It is just a Java library of third-party authorized login, It's smaller and easier to use. JustAuth is the best third-party login tool written in JAVA.
Source Code[gitee](https://gitee.com/yadong.zhang/JustAuth) | [github](https://github.com/zhangyd-c/JustAuth)
Docs[Reference Doc](https://justauth.wiki)
Docs[Reference Doc](https://www.justauth.cn)
## Features
@@ -90,34 +52,28 @@ Docs[Reference Doc](https://justauth.wiki)
## Quick start
- Add maven dependency
### Add maven dependency
- Add JustAuth dependency
These artifacts are available from Maven Central:
```xml
<dependency>
<groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId>
<version>1.15.8-beta.2</version>
<version>{latest-version}</version>
</dependency>
```
- Using JustAuth
```java
// Create authorization request
AuthRequest authRequest = new AuthGiteeRequest(AuthConfig.builder()
.clientId("clientId")
.clientSecret("clientSecret")
.redirectUri("redirectUri")
.build());
// Generate authorization url
authRequest.authorize("state");
// After authorization to login, it will return: code(auth_code(Alipay only)),state, After version 1.8.0, you can use the AuthCallback as a parameter to the callback interface
// Note: JustAuth saves state for 3 minutes by default. If it is not used within 3 minutes, the expired state will be cleared automatically.
authRequest.login(callback);
```
Note, that since [v1.14.0](https://gitee.com/yadong.zhang/JustAuth/releases/v1.14.0) JustAuth has been integrated by default with [simple-http](https://github.com/xkcoding/simple-http) as the HTTP general interface (see the update [JustAuth 1.14.0 release! Perfect decoupling of HTTP tools](https://mp.weixin.qq.com/s?__biz=MzA3NDk3OTIwMg==&mid=2450633197&idx=1&sn=11e625b307db62b2f1c4e82f7744b2a2&chksm=88929300bfe51a16562b45592a264482ae2c74c6dbfa4a3aa9611ad4fea4a9be5b1f0545527d&token=1093833287&lang=zh_CN#rd)). Since most projects already integrate HTTP tools such as OkHttp3, apache HttpClient, and hutool-http), in order to reduce unnecessary dependencies,Starting from [v1.14.0](https://gitee.com/yadong.zhang/JustAuth/releases/v1.14.0), JustAuth will not integrate hutool-http by default. If the developer's project is new or there is no integrated HTTP implementation tool in the project, please add the corresponding HTTP implementation class by yourself. Alternative dependencies are as follows:
> **latest-version**
> - CURRENT: ![](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
@@ -148,6 +104,68 @@ Note, that since [v1.14.0](https://gitee.com/yadong.zhang/JustAuth/releases/v1.1
</dependency>
```
### Using JustAuth API
#### Simple
```java
// Create authorization request
AuthRequest authRequest = new AuthGiteeRequest(AuthConfig.builder()
.clientId("clientId")
.clientSecret("clientSecret")
.redirectUri("redirectUri")
.build());
// Generate authorization page url
authRequest.authorize("state");
// Get token and userinfo
authRequest.login(callback);
```
#### Builder 1. Use unchanging `AuthConfig`
```java
// Create authorization request
AuthRequest authRequest = AuthRequestBuilder.builder()
.source("github")
.authConfig(AuthConfig.builder()
.clientId("clientId")
.clientSecret("clientSecret")
.redirectUri("redirectUri")
.build())
.build();
```
#### Builder 2. Use dynamic `AuthConfig`
```java
// Create authorization request
AuthRequest authRequest = AuthRequestBuilder.builder()
.source("gitee")
.authConfig((source) -> {
// Use source to dynamically get AuthConfig
// Here you can flexibly take the configuration from sql or take the configuration from the configuration file
return AuthConfig.builder()
.clientId("clientId")
.clientSecret("clientSecret")
.redirectUri("redirectUri")
.build();
})
.build();
```
#### Builder 3. Support custom platform
```java
AuthRequest authRequest = AuthRequestBuilder.builder()
// Key point: configure the custom implementation of AuthSource
.extendSource(AuthExtendSource.values())
// Enum name in AuthExtendSource
.source("other")
// ... Do other things
.build();
```
## Contributions
1. Fork this project to your repository
@@ -162,11 +180,11 @@ I look forward to your joining us.
## Contributors
[contributors](https://justauth.wiki/#/contributors)
[contributors](https://www.justauth.cn/contributors.html)
## Change Logs
[CHANGELOGS](https://justauth.wiki/#/update)
[CHANGELOGS](https://www.justauth.cn/update.html)
## Recommend
+184 -99
View File
@@ -1,12 +1,15 @@
<p align="center">
<a href="https://justauth.wiki"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/Justauth.png" width="400"></a>
<a href="https://www.justauth.cn"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/Justauth.png" width="400"></a>
</p>
<p align="center">
<strong>Login, so easy.</strong>
</p>
<p align="center">
<a target="_blank" href="https://search.maven.org/search?q=JustAuth">
<img src="https://img.shields.io/badge/Maven%20Central-1.15.8-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,77 +17,36 @@
<a target="_blank" href="https://www.oracle.com/technetwork/java/javase/downloads/index.html">
<img src="https://img.shields.io/badge/JDK-1.8+-green.svg" ></img>
</a>
<a target="_blank" href="https://apidoc.gitee.com/yadong.zhang/JustAuth/" title="API文档">
<img src="https://img.shields.io/badge/Api%20Docs-1.15.8-orange" ></img>
</a>
<a target="_blank" href="https://justauth.wiki" title="参考文档">
<a target="_blank" href="https://www.justauth.cn" title="参考文档">
<img src="https://img.shields.io/badge/Docs-latest-blueviolet.svg" ></img>
</a>
<a href="https://codecov.io/gh/zhangyd-c/JustAuth">
<img src="https://codecov.io/gh/zhangyd-c/JustAuth/branch/master/graph/badge.svg" />
<a href="https://codecov.io/gh/justauth/JustAuth">
<img src="https://codecov.io/gh/justauth/JustAuth/branch/master/graph/badge.svg?token=zYiAqd9aFz" />
</a>
<a href='https://gitee.com/yadong.zhang/JustAuth/stargazers'>
<img src='https://gitee.com/yadong.zhang/JustAuth/badge/star.svg?theme=white' alt='star'></img>
<img src='https://gitee.com/yadong.zhang/JustAuth/badge/star.svg?theme=gvp' alt='star'></img>
</a>
<a target="_blank" href='https://github.com/zhangyd-c/JustAuth'>
<img src="https://img.shields.io/github/stars/zhangyd-c/JustAuth.svg?style=social" alt="github star"></img>
</a>
</p>
<center>
<table>
<tr>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/gitee.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/github.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/weibo.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/dingtalk.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/baidu.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/coding.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/tencentCloud.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/oschina.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/alipay.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/qq.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/wechat.png" width="20" title="微信开放平台"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/taobao.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/google.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/facebook.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/douyin.png" width="20"></td>
</tr>
</table>
<table>
<tr>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/linkedin.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/microsoft.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/mi.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/toutiao.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/teambition.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/renren.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/pinterest.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/stackoverflow.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/huawei.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/wechat.png" width="20" title="微信企业版"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/csdn.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/kujiale.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/gitlab.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/meituan.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/eleme.png" width="20"></td>
<td align="center" width="200"><img src="https://gitee.com/yadong.zhang/static/raw/master/JustAuth/twitter.png" width="20"></td>
</tr>
</table>
<center><a href="https://justauth.wiki/#/?id=%E5%B7%B2%E9%9B%86%E6%88%90%E7%9A%84%E5%B9%B3%E5%8F%B0" target="_blank">查看更多</a></center>
</center>
-------------------------------------------------------------------------------
<p align="center">
<img src='./docs/media/75a3c076.png' alt='star'></img>
</p>
-------------------------------------------------------------------------------
QQ 群:230017570
微信群:justauth (备注`justauth`或者`ja`
帮助文档:[justauth.wiki](https://justauth.wiki)
帮助文档:[www.justauth.cn](https://www.justauth.cn)
## 什么是 JustAuth
JustAuth,如你所见,它仅仅是一个**第三方授权登录**的**工具类库**,它可以让我们脱离繁琐的第三方登录 SDK,让登录变得**So easy!**
JustAuth 集成了诸如:Github、Gitee、支付宝、新浪微博、微信、Google、Facebook、Twitter、StackOverflow等国内外数十家第三方平台。更多请参考<a href="https://justauth.wiki/#/?id=%E5%B7%B2%E9%9B%86%E6%88%90%E7%9A%84%E5%B9%B3%E5%8F%B0" target="_blank">已集成的平台</a>
JustAuth 集成了诸如:Github、Gitee、支付宝、新浪微博、微信、Google、Facebook、Twitter、StackOverflow等国内外数十家第三方平台。更多请参考<a href="https://www.justauth.cn" target="_blank">已集成的平台</a>
## 有哪些特点?
@@ -93,24 +55,94 @@ JustAuth 集成了诸如:Github、Gitee、支付宝、新浪微博、微信、
## 有哪些功能?
- 集成国内外数十家第三方平台,实现快速接入。<a href="https://justauth.wiki/#/?id=%E5%B7%B2%E9%9B%86%E6%88%90%E7%9A%84%E5%B9%B3%E5%8F%B0" target="_blank">参考文档</a>
- 自定义 State 缓存,支持各种分布式缓存组件。<a href="https://justauth.wiki/#/customize-the-state-cache" target="_blank">参考文档</a>
- 自定义 OAuth 平台,更容易适配自有的 OAuth 服务。<a href="https://justauth.wiki/#/customize-the-oauth" target="_blank">参考文档</a>
- 自定义 Http 实现,选择权完全交给开发者,不会单独依赖某一具体实现。<a href="https://justauth.wiki/#/customize-the-oauth" target="_blank">参考文档</a>
- 自定义 Scope,支持更完善的授权体系。<a href="https://justauth.wiki" target="_blank">参考文档</a>
- 更多...<a href="https://justauth.wiki" target="_blank">参考文档</a>
- 集成国内外数十家第三方平台,实现快速接入。<a href="https://www.justauth.cn/quickstart/how-to-use.html" target="_blank">参考文档</a>
- 自定义 State 缓存,支持各种分布式缓存组件。<a href="https://www.justauth.cn/features/customize-the-state-cache.html" target="_blank">参考文档</a>
- 自定义 OAuth 平台,更容易适配自有的 OAuth 服务。<a href="https://www.justauth.cn/features/customize-the-oauth.html" target="_blank">参考文档</a>
- 自定义 Http 实现,选择权完全交给开发者,不会单独依赖某一具体实现。<a href="https://www.justauth.cn/quickstart/how-to-use.html#%E4%BD%BF%E7%94%A8%E6%96%B9%E5%BC%8F" target="_blank">参考文档</a>
- 自定义 Scope,支持更完善的授权体系。<a href="https://www.justauth.cn/features/customize-scopes.html" target="_blank">参考文档</a>
- 更多...<a href="https://www.justauth.cn" target="_blank">参考文档</a>
## 快速开始
- 引入依赖
### 引入依赖
```xml
<dependency>
<groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId>
<version>1.15.8</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()
@@ -125,60 +157,113 @@ 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();
```
## 赞助和支持
感谢以下赞助商的支持:
[我要赞助](https://www.justauth.cn/sponsor.html)
## JustAuth 的用户
有很多公司、组织和个人把 JustAuth 用于学习、研究、生产环境和商业产品中,包括(但不限于):
![](docs/users/4ca0177c.png)
[![](docs/users/col.png)](https://www.mochiwang.com "给作者提供云写作的一个工具")![](docs/users/bjgyol.png)![](docs/users/foresealife.png)![](docs/users/sevnce.png)
![](docs/users/bladex.png)![](docs/users/gun.png)![](docs/users/sika.jpg)![](docs/users/maxkey.png)![](docs/users/shiroaction.png)![](docs/users/xkcoding.png)
怎么没有我?[加入]()
怎么没有我?[登记](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://www.justauth.cn)
## 鸣谢
# 鸣谢
- 感谢 JetBrains 提供的免费开源 License
<img src="https://images.gitee.com/uploads/images/2020/0406/220236_f5275c90_5531506.png" alt="图片引用自lets-mica" style="float:left;">
<a href="https://www.producthunt.com/posts/justauth?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-justauth" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=196886&theme=dark" alt="JustAuth - Login, so easy! | Product Hunt Embed" style="width: 250px; height: 54px;" width="250px" height="54px" /></a>
<p>
<img src="https://images.gitee.com/uploads/images/2020/0406/220236_f5275c90_5531506.png" alt="图片引用自lets-mica" style="float:left;">
</p>
## 其他
- [CONTRIBUTORS](https://justauth.wiki/#/contributors)
- [CHANGELOGS](https://justauth.wiki/#/update)
- [PLAN](https://gitee.com/yadong.zhang/JustAuth/issues/IUGRK)
- [CONTRIBUTORS](https://www.justauth.cn/contributors.html)
- [CHANGELOGS](https://www.justauth.cn/update.html)
- [PLAN](https://gitee.com/yadong.zhang/JustAuth/issues/IUGRK)
## 贡献者列表
[![contributors](https://whnb.wang/contributors/yadong.zhang/JustAuth)](https://whnb.wang)
## Stars 趋势
### Gitee
[![Stargazers over time](https://whnb.wang/img/yadong.zhang/JustAuth?e=604800)](https://whnb.wang/yadong.zhang/JustAuth?e=604800)
### Github
[![Stargazers over time](https://starchart.cc/justauth/JustAuth.svg)](https://starchart.cc/justauth/JustAuth)
### ProductHunt
<a href="https://www.producthunt.com/posts/justauth?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-justauth" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=196886&theme=dark" alt="JustAuth - Login, so easy! | Product Hunt Embed" style="width: 250px; height: 54px;" width="250px" height="54px" /></a>
+1
View File
@@ -0,0 +1 @@
git pull origin dev && git pull github dev
+1
View File
@@ -0,0 +1 @@
git push origin dev && git push github dev
+1
View File
@@ -0,0 +1 @@
git push origin master && git push github master
+1 -1
View File
@@ -1 +1 @@
1.15.8
1.16.6
+1 -1
View File
@@ -16,7 +16,7 @@
</head>
<body>
<script>
window.location.href = "https://justauth.wiki";
window.location.href = "https://www.justauth.cn";
</script>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

+4
View File
@@ -96,6 +96,10 @@ _注:非全部平台,部分平台可能不存在图例_
![授权Stack Overflow](https://images.gitee.com/uploads/images/2019/0718/192639_cc301ba7_784199.png "授权Stack Overflow")
#### 授权afdian
![授权afdian](https://img.fastmirror.net/s/2023/03/24/641d63a8c19b5.png "授权afDian")
#### 授权Twitter
![授权Twitter]( "授权Twitter")
+12
View File
@@ -15,6 +15,18 @@ case "$1" in
'updv')
bin/updVersion.sh $2
;;
'ppd')
bin/pull-dev.sh
;;
'pd')
bin/push-dev.sh
;;
'p')
bin/push.sh
;;
'd')
bin/deploy.sh
;;
*)
help
esac
+36 -12
View File
@@ -6,12 +6,12 @@
<groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId>
<version>1.15.8</version>
<version>1.16.6</version>
<name>JustAuth</name>
<url>https://gitee.com/yadong.zhang/JustAuth</url>
<description>
小而全而美的第三方登录开源组件。目前已支持Github、Gitee、微博、钉钉、百度、Coding、腾讯云开发者平台、OSChina、支付宝、QQ、微信、淘宝、Google、Facebook、抖音、领英、小米、微软、今日头条、Teambition、StackOverflow、Pinterest、人人、华为、企业微信、酷家乐、Gitlab、美团、饿了么推特等第三方平台的授权登录。 Login, so easy!
小而全而美的第三方登录开源组件。目前已支持Github、Gitee、微博、钉钉、百度、Coding、腾讯云开发者平台、OSChina、支付宝、QQ、微信、淘宝、Google、Facebook、抖音、领英、小米、微软、今日头条、Teambition、StackOverflow、Pinterest、人人、华为、企业微信、酷家乐、Gitlab、美团、饿了么推特、飞书、京东、阿里云、喜马拉雅、Amazon、Slack和Line等第三方平台的授权登录。 Login, so easy!
</description>
<licenses>
@@ -52,16 +52,16 @@
<maven.compiler.target>1.8</maven.compiler.target>
<maven-source.version>2.2.1</maven-source.version>
<maven-compiler.version>3.8.1</maven-compiler.version>
<maven-javadoc.version>3.1.0</maven-javadoc.version>
<maven-javadoc.version>2.9.1</maven-javadoc.version>
<cobertura-version>2.7</cobertura-version>
<maven-surefire-version>2.20</maven-surefire-version>
<maven-gpg-version>1.6</maven-gpg-version>
<maven.test.skip>false</maven.test.skip>
<simple-http.version>1.0.3</simple-http.version>
<lombok-version>1.18.10</lombok-version>
<junit-version>4.13.1</junit-version>
<fastjson-version>1.2.73</fastjson-version>
<alipay-sdk-version>4.8.10.ALL</alipay-sdk-version>
<simple-http.version>1.0.5</simple-http.version>
<lombok-version>1.18.20</lombok-version>
<junit-version>4.13.2</junit-version>
<fastjson-version>1.2.83</fastjson-version>
<alipay-sdk-version>4.17.5.ALL</alipay-sdk-version>
<jacoco-version>0.8.2</jacoco-version>
</properties>
@@ -93,6 +93,12 @@
<artifactId>alipay-sdk-java</artifactId>
<version>${alipay-sdk-version}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<artifactId>fastjson</artifactId>
<groupId>com.alibaba</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
@@ -135,6 +141,9 @@
</goals>
</execution>
</executions>
<configuration>
<additionalparam>${javadoc.opts}</additionalparam>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -154,6 +163,15 @@
</plugins>
</build>
<profiles>
<profile>
<id>snapshot</id>
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
</profile>
<profile>
<id>release</id>
<build>
@@ -219,10 +237,6 @@
</plugins>
</build>
<distributionManagement>
<snapshotRepository>
<id>sonatype-nexus-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</snapshotRepository>
<repository>
<id>sonatype-nexus-staging</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
@@ -260,5 +274,15 @@
</snapshotRepository>
</distributionManagement>
</profile>
<!-- 禁用 Javadoc 注释检查 -->
<profile>
<id>disable-javadoc-doclint</id>
<activation>
<jdk>[1.8,)</jdk>
</activation>
<properties>
<javadoc.opts>-Xdoclint:none</javadoc.opts>
</properties>
</profile>
</profiles>
</project>
@@ -0,0 +1,101 @@
package me.zhyd.oauth;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.config.AuthDefaultSource;
import me.zhyd.oauth.config.AuthSource;
import me.zhyd.oauth.enums.AuthResponseStatus;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.request.AuthDefaultRequest;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.StringUtils;
import java.util.Arrays;
import java.util.function.Function;
/**
* 快捷的构建 AuthRequest
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @author ngcly
* @version 1.0.0
* @since 1.16.3
*/
public class AuthRequestBuilder {
private String source;
private AuthConfig authConfig;
private AuthStateCache authStateCache;
private AuthSource[] extendSource;
private AuthRequestBuilder() {
}
public static AuthRequestBuilder builder() {
return new AuthRequestBuilder();
}
public AuthRequestBuilder source(String source) {
this.source = source;
return this;
}
public AuthRequestBuilder authConfig(AuthConfig authConfig) {
this.authConfig = authConfig;
return this;
}
public AuthRequestBuilder authConfig(Function<String, AuthConfig> authConfig) {
this.authConfig = authConfig.apply(this.source);
return this;
}
public AuthRequestBuilder authStateCache(AuthStateCache authStateCache) {
this.authStateCache = authStateCache;
return this;
}
public AuthRequestBuilder extendSource(AuthSource... extendSource) {
this.extendSource = extendSource;
return this;
}
public AuthRequest build() {
if (StringUtils.isEmpty(this.source) || null == this.authConfig) {
throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED);
}
// 合并 JustAuth 默认的 AuthDefaultSource 和 开发者自定义的 AuthSource
AuthSource[] sources = this.concat(AuthDefaultSource.values(), extendSource);
// 筛选符合条件的 AuthSource
AuthSource source = Arrays.stream(sources).distinct()
.filter(authSource -> authSource.getName().equalsIgnoreCase(this.source))
.findAny()
.orElseThrow(() -> new AuthException(AuthResponseStatus.NOT_IMPLEMENTED));
Class<? extends AuthDefaultRequest> targetClass = source.getTargetClass();
if (null == targetClass) {
throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED);
}
try {
if (this.authStateCache == null) {
return targetClass.getDeclaredConstructor(AuthConfig.class).newInstance(this.authConfig);
} else {
return targetClass.getDeclaredConstructor(AuthConfig.class, AuthStateCache.class).newInstance(this.authConfig, this.authStateCache);
}
} catch (Exception e) {
e.printStackTrace();
throw new AuthException(AuthResponseStatus.NOT_IMPLEMENTED);
}
}
private AuthSource[] concat(AuthSource[] first, AuthSource[] second) {
if (null == second || second.length == 0) {
return first;
}
AuthSource[] result = new AuthSource[first.length + second.length];
System.arraycopy(first, 0, result, 0, first.length);
System.arraycopy(second, 0, result, first.length, second.length);
return result;
}
}
@@ -2,8 +2,8 @@ package me.zhyd.oauth.config;
import com.xkcoding.http.config.HttpConfig;
import lombok.*;
import me.zhyd.oauth.enums.scope.AuthScope;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.utils.StringUtils;
import java.util.List;
@@ -38,7 +38,10 @@ public class AuthConfig {
/**
* 支付宝公钥:当选择支付宝登录时,该值可用
* 对应“RSA2(SHA256)密钥”中的“支付宝公钥”
*
* @deprecated 请使用AuthAlipayRequest的构造方法设置"alipayPublicKey"
*/
@Deprecated
private String alipayPublicKey;
/**
@@ -66,13 +69,24 @@ public class AuthConfig {
private String agentId;
/**
* 使用 Coding 登录时,需要传该值。
* <p>
* 团队域名前缀,比如以“ https://justauth.coding.net/ ”为例,{@code codingGroupName} = justauth
* 企业微信第三方授权用户类型,member|admin
*
* @since 1.15.5
* @since 1.10.0
*/
private String codingGroupName;
private String usertype;
/**
* 域名前缀。
* <p>
* 使用 Coding 登录和 Okta 登录时,需要传该值。
* <p>
* Coding 登录:团队域名前缀,比如以“ https://justauth.coding.net ”为例,{@code domainPrefix} = justauth
* <p>
* Okta 登录:Okta 账号域名前缀,比如以“ https://justauth.okta.com ”为例,{@code domainPrefix} = justauth
*
* @since 1.16.0
*/
private String domainPrefix;
/**
* 针对国外服务可以单独设置代理
@@ -110,4 +124,66 @@ public class AuthConfig {
* @since 1.15.7
*/
private List<String> scopes;
/**
* 设备ID, 设备唯一标识ID
*
* @since 1.15.8
*/
private String deviceId;
/**
* 喜马拉雅:客户端操作系统类型,1-iOS系统,2-Android系统,3-Web
*
* @since 1.15.9
*/
private Integer clientOsType;
/**
* 喜马拉雅:客户端包名,如果 {@link AuthConfig#clientOsType} 为1或2时必填。对Android客户端是包名,对IOS客户端是Bundle ID
*
* @since 1.15.9
*/
private String packId;
/**
* 是否开启 PKCE 模式,该配置仅用于支持 PKCE 模式的平台,针对无服务应用,不推荐使用隐式授权,推荐使用 PKCE 模式
*
* @since 1.15.9
*/
private boolean pkce;
/**
* Okta 授权服务器的 ID, 默认为 default。如果要使用自定义授权服务,此处传实际的授权服务器 ID(一个随机串)
* <p>
* 创建自定义授权服务器,请参考:
* <p>
* ① https://developer.okta.com/docs/concepts/auth-servers
* <p>
* ② https://developer.okta.com/docs/guides/customize-authz-server
*
* @since 1.16.0
*/
private String authServerId;
/**
* 忽略校验 {@code redirectUri} 参数,默认不开启。当 {@code ignoreCheckRedirectUri} 为 {@code true} 时,
* {@link me.zhyd.oauth.utils.AuthChecker#checkConfig(AuthConfig, AuthSource)} 将不会校验 {@code redirectUri} 的合法性。
*
* @since 1.16.1
*/
private boolean ignoreCheckRedirectUri;
/**
* 适配 builder 模式 set 值的情况
*
* @return authServerId
*/
public String getAuthServerId() {
return StringUtils.isEmpty(authServerId) ? "default" : authServerId;
}
/**
* Microsoft Entra ID(原微软 AAD)中的租户 ID
*/
private String tenantId;
}
@@ -2,6 +2,7 @@ package me.zhyd.oauth.config;
import me.zhyd.oauth.enums.AuthResponseStatus;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.request.*;
/**
* JustAuth内置的各api需要的url, 用枚举类分平台类型管理
@@ -28,6 +29,11 @@ public enum AuthDefaultSource implements AuthSource {
public String userInfo() {
return "https://api.github.com/user";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthGithubRequest.class;
}
},
/**
* 新浪微博
@@ -52,6 +58,11 @@ public enum AuthDefaultSource implements AuthSource {
public String revoke() {
return "https://api.weibo.com/oauth2/revokeoauth2";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthWeiboRequest.class;
}
},
/**
* gitee
@@ -71,9 +82,14 @@ public enum AuthDefaultSource implements AuthSource {
public String userInfo() {
return "https://gitee.com/api/v5/user";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthGiteeRequest.class;
}
},
/**
* 钉钉
* 钉钉扫码登录
*/
DINGTALK {
@Override
@@ -90,6 +106,35 @@ public enum AuthDefaultSource implements AuthSource {
public String userInfo() {
return "https://oapi.dingtalk.com/sns/getuserinfo_bycode";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthDingTalkRequest.class;
}
},
/**
* 钉钉账号登录
*/
DINGTALK_ACCOUNT {
@Override
public String authorize() {
return "https://oapi.dingtalk.com/connect/oauth2/sns_authorize";
}
@Override
public String accessToken() {
return DINGTALK.accessToken();
}
@Override
public String userInfo() {
return DINGTALK.userInfo();
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthDingTalkAccountRequest.class;
}
},
/**
* 百度
@@ -119,6 +164,11 @@ public enum AuthDefaultSource implements AuthSource {
public String refresh() {
return "https://openapi.baidu.com/oauth/2.0/token";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthBaiduRequest.class;
}
},
/**
* csdn
@@ -138,10 +188,15 @@ public enum AuthDefaultSource implements AuthSource {
public String userInfo() {
return "https://api.csdn.net/user/getinfo";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthCsdnRequest.class;
}
},
/**
* Coding
*
* <p>
* 参考 https://help.coding.net/docs/project/open/oauth.html#%E7%94%A8%E6%88%B7%E6%8E%88%E6%9D%83 中的说明,
* 新版的 coding API 地址需要传入用户团队名,这儿使用动态参数,方便在 request 中使用
*/
@@ -160,6 +215,11 @@ public enum AuthDefaultSource implements AuthSource {
public String userInfo() {
return "https://%s.coding.net/api/account/current_user";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthCodingRequest.class;
}
},
/**
* oschina 开源中国
@@ -179,6 +239,11 @@ public enum AuthDefaultSource implements AuthSource {
public String userInfo() {
return "https://www.oschina.net/action/openapi/user";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthOschinaRequest.class;
}
},
/**
* 支付宝
@@ -198,6 +263,11 @@ public enum AuthDefaultSource implements AuthSource {
public String userInfo() {
return "https://openapi.alipay.com/gateway.do";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthAlipayRequest.class;
}
},
/**
* QQ
@@ -222,6 +292,11 @@ public enum AuthDefaultSource implements AuthSource {
public String refresh() {
return "https://graph.qq.com/oauth2.0/token";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthQqRequest.class;
}
},
/**
* 微信开放平台
@@ -246,6 +321,11 @@ public enum AuthDefaultSource implements AuthSource {
public String refresh() {
return "https://api.weixin.qq.com/sns/oauth2/refresh_token";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthWeChatOpenRequest.class;
}
},
/**
* 微信公众平台
@@ -270,6 +350,11 @@ public enum AuthDefaultSource implements AuthSource {
public String refresh() {
return "https://api.weixin.qq.com/sns/oauth2/refresh_token";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthWeChatMpRequest.class;
}
},
/**
* 淘宝
@@ -289,6 +374,11 @@ public enum AuthDefaultSource implements AuthSource {
public String userInfo() {
throw new AuthException(AuthResponseStatus.UNSUPPORTED);
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthTaobaoRequest.class;
}
},
/**
* Google
@@ -308,6 +398,11 @@ public enum AuthDefaultSource implements AuthSource {
public String userInfo() {
return "https://www.googleapis.com/oauth2/v3/userinfo";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthGoogleRequest.class;
}
},
/**
* Facebook
@@ -315,17 +410,22 @@ public enum AuthDefaultSource implements AuthSource {
FACEBOOK {
@Override
public String authorize() {
return "https://www.facebook.com/v3.3/dialog/oauth";
return "https://www.facebook.com/v18.0/dialog/oauth";
}
@Override
public String accessToken() {
return "https://graph.facebook.com/v3.3/oauth/access_token";
return "https://graph.facebook.com/v18.0/oauth/access_token";
}
@Override
public String userInfo() {
return "https://graph.facebook.com/v3.3/me";
return "https://graph.facebook.com/v18.0/me";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthFacebookRequest.class;
}
},
/**
@@ -351,6 +451,11 @@ public enum AuthDefaultSource implements AuthSource {
public String refresh() {
return "https://open.douyin.com/oauth/refresh_token/";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthDouyinRequest.class;
}
},
/**
* 领英
@@ -375,6 +480,11 @@ public enum AuthDefaultSource implements AuthSource {
public String refresh() {
return "https://www.linkedin.com/oauth/v2/accessToken";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthLinkedinRequest.class;
}
},
/**
* 微软
@@ -382,12 +492,12 @@ public enum AuthDefaultSource implements AuthSource {
MICROSOFT {
@Override
public String authorize() {
return "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
return "https://login.microsoftonline.com/%s/oauth2/v2.0/authorize";
}
@Override
public String accessToken() {
return "https://login.microsoftonline.com/common/oauth2/v2.0/token";
return "https://login.microsoftonline.com/%s/oauth2/v2.0/token";
}
@Override
@@ -397,8 +507,40 @@ public enum AuthDefaultSource implements AuthSource {
@Override
public String refresh() {
return "https://login.microsoftonline.com/common/oauth2/v2.0/token";
return "https://login.microsoftonline.com/%s/oauth2/v2.0/token";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthMicrosoftRequest.class;
}
},
/**
* 微软中国(世纪互联)
*/
MICROSOFT_CN {
@Override
public String authorize() {
return "https://login.partner.microsoftonline.cn/%s/oauth2/v2.0/authorize";
}
@Override
public String accessToken() {
return "https://login.partner.microsoftonline.cn/%s/oauth2/v2.0/token";
}
@Override
public String userInfo() {
return "https://microsoftgraph.chinacloudapi.cn/v1.0/me";
}
@Override
public String refresh() {
return "https://login.partner.microsoftonline.cn/%s/oauth2/v2.0/token";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() { return AuthMicrosoftCnRequest.class; }
},
/**
* 小米
@@ -423,6 +565,11 @@ public enum AuthDefaultSource implements AuthSource {
public String refresh() {
return "https://account.xiaomi.com/oauth2/token";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthMiRequest.class;
}
},
/**
* 今日头条
@@ -442,6 +589,11 @@ public enum AuthDefaultSource implements AuthSource {
public String userInfo() {
return "https://open.snssdk.com/data/user_profile";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthToutiaoRequest.class;
}
},
/**
* Teambition
@@ -466,6 +618,11 @@ public enum AuthDefaultSource implements AuthSource {
public String userInfo() {
return "https://api.teambition.com/users/me";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthTeambitionRequest.class;
}
},
/**
@@ -491,6 +648,11 @@ public enum AuthDefaultSource implements AuthSource {
public String userInfo() {
return "https://api.renren.com/v2/user/get";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthRenrenRequest.class;
}
},
/**
@@ -511,6 +673,11 @@ public enum AuthDefaultSource implements AuthSource {
public String userInfo() {
return "https://api.pinterest.com/v1/me";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthPinterestRequest.class;
}
},
/**
@@ -531,6 +698,11 @@ public enum AuthDefaultSource implements AuthSource {
public String userInfo() {
return "https://api.stackexchange.com/2.2/me";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthStackOverflowRequest.class;
}
},
/**
@@ -558,10 +730,15 @@ public enum AuthDefaultSource implements AuthSource {
public String refresh() {
return "https://oauth-login.cloud.huawei.com/oauth2/v2/token";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthHuaweiRequest.class;
}
},
/**
* 企业微信
* 企业微信二维码登录
*
* @since 1.10.0
*/
@@ -580,6 +757,74 @@ public enum AuthDefaultSource implements AuthSource {
public String userInfo() {
return "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthWeChatEnterpriseQrcodeRequest.class;
}
},
/**
* 企业微信二维码第三方登录
*/
WECHAT_ENTERPRISE_QRCODE_THIRD {
/**
* 授权的api
*
* @return url
*/
@Override
public String authorize() {
return "https://open.work.weixin.qq.com/wwopen/sso/3rd_qrConnect";
}
/**
* 获取accessToken的api
*
* @return url
*/
@Override
public String accessToken() {
return "https://qyapi.weixin.qq.com/cgi-bin/service/get_provider_token";
}
/**
* 获取用户信息的api
*
* @return url
*/
@Override
public String userInfo() {
return "https://qyapi.weixin.qq.com/cgi-bin/service/get_login_info";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthWeChatEnterpriseThirdQrcodeRequest.class;
}
},
/**
* 企业微信网页登录
*/
WECHAT_ENTERPRISE_WEB {
@Override
public String authorize() {
return "https://open.weixin.qq.com/connect/oauth2/authorize";
}
@Override
public String accessToken() {
return "https://qyapi.weixin.qq.com/cgi-bin/gettoken";
}
@Override
public String userInfo() {
return "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthWeChatEnterpriseWebRequest.class;
}
},
/**
@@ -607,6 +852,11 @@ public enum AuthDefaultSource implements AuthSource {
public String refresh() {
return "https://oauth.kujiale.com/oauth2/auth/token/refresh";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthKujialeRequest.class;
}
},
/**
@@ -629,6 +879,11 @@ public enum AuthDefaultSource implements AuthSource {
public String userInfo() {
return "https://gitlab.com/api/v4/user";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthGitlabRequest.class;
}
},
/**
@@ -656,6 +911,11 @@ public enum AuthDefaultSource implements AuthSource {
public String refresh() {
return "https://openapi.waimai.meituan.com/oauth/refresh_token";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthMeituanRequest.class;
}
},
/**
@@ -685,6 +945,11 @@ public enum AuthDefaultSource implements AuthSource {
public String refresh() {
return "https://open-api.shop.ele.me/token";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthElemeRequest.class;
}
},
/**
@@ -705,35 +970,46 @@ public enum AuthDefaultSource implements AuthSource {
@Override
public String userInfo() {
return "https://api.twitter.com/1.1/users/show.json";
return "https://api.twitter.com/1.1/account/verify_credentials.json";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthTwitterRequest.class;
}
},
/**
* 飞书
* 注意:该平台暂时存在问题,请不要使用。待修复完成后会重新发版
* 飞书平台,企业自建应用授权登录,原逻辑由 beacon 集成于 1.14.0 版,但最新的飞书 api 已修改,并且飞书平台一直为 {@code Deprecated} 状态
* <p>
* 所以,最终修改该平台的实际发布版本为 1.15.9
*
* @since 1.14.0
* @since 1.15.9
*/
FEISHU {
@Override
public String authorize() {
return "https://open.feishu.cn/connect/qrconnect/page/sso/";
return "https://open.feishu.cn/open-apis/authen/v1/index";
}
@Override
public String accessToken() {
return "https://open.feishu.cn/connect/qrconnect/oauth2/access_token/";
return "https://open.feishu.cn/open-apis/authen/v1/access_token";
}
@Override
public String userInfo() {
return "https://open.feishu.cn/connect/qrconnect/oauth2/user_info/";
return "https://open.feishu.cn/open-apis/authen/v1/user_info";
}
@Override
public String refresh() {
return "https://open.feishu.cn/connect/qrconnect/oauth2/access_token/";
return "https://open.feishu.cn/open-apis/authen/v1/refresh_access_token";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthFeishuRequest.class;
}
},
/**
@@ -761,6 +1037,11 @@ public enum AuthDefaultSource implements AuthSource {
public String refresh() {
return "https://open-oauth.jd.com/oauth2/refresh_token";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthJdRequest.class;
}
},
/**
@@ -786,6 +1067,235 @@ public enum AuthDefaultSource implements AuthSource {
public String refresh() {
return "https://oauth.aliyun.com/v1/token";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthAliyunRequest.class;
}
},
/**
* 喜马拉雅
*/
XMLY {
@Override
public String authorize() {
return "https://api.ximalaya.com/oauth2/js/authorize";
}
@Override
public String accessToken() {
return "https://api.ximalaya.com/oauth2/v2/access_token";
}
@Override
public String userInfo() {
return "https://api.ximalaya.com/profile/user_info";
}
@Override
public String refresh() {
return "https://oauth.aliyun.com/v1/token";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthXmlyRequest.class;
}
},
/**
* Amazon
*
* @since 1.16.0
*/
AMAZON {
@Override
public String authorize() {
return "https://www.amazon.com/ap/oa";
}
@Override
public String accessToken() {
return "https://api.amazon.com/auth/o2/token";
}
@Override
public String userInfo() {
return "https://api.amazon.com/user/profile";
}
@Override
public String refresh() {
return "https://api.amazon.com/auth/o2/token";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthAmazonRequest.class;
}
},
/**
* Slack
*
* @since 1.16.0
*/
SLACK {
@Override
public String authorize() {
return "https://slack.com/oauth/v2/authorize";
}
/**
* 该 API 获取到的是 access token
*
* https://slack.com/api/oauth.token 获取到的是 workspace token
*
* @return String
*/
@Override
public String accessToken() {
return "https://slack.com/api/oauth.v2.access";
}
@Override
public String userInfo() {
return "https://slack.com/api/users.info";
}
@Override
public String revoke() {
return "https://slack.com/api/auth.revoke";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthSlackRequest.class;
}
},
/**
* line
*
* @since 1.16.0
*/
LINE {
@Override
public String authorize() {
return "https://access.line.me/oauth2/v2.1/authorize";
}
@Override
public String accessToken() {
return "https://api.line.me/oauth2/v2.1/token";
}
@Override
public String userInfo() {
return "https://api.line.me/v2/profile";
}
@Override
public String refresh() {
return "https://api.line.me/oauth2/v2.1/token";
}
@Override
public String revoke() {
return "https://api.line.me/oauth2/v2.1/revoke";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthLineRequest.class;
}
},
/**
* Okta
* <p>
* 团队/组织的域名不同,此处通过配置动态组装
*
* @since 1.16.0
*/
OKTA {
@Override
public String authorize() {
return "https://%s.okta.com/oauth2/%s/v1/authorize";
}
@Override
public String accessToken() {
return "https://%s.okta.com/oauth2/%s/v1/token";
}
@Override
public String refresh() {
return "https://%s.okta.com/oauth2/%s/v1/token";
}
@Override
public String userInfo() {
return "https://%s.okta.com/oauth2/%s/v1/userinfo";
}
@Override
public String revoke() {
return "https://%s.okta.com/oauth2/%s/v1/revoke";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthOktaRequest.class;
}
},
/**
* 程序员客栈
*
* @since 1.16.2
*/
PROGINN {
@Override
public String authorize() {
return "https://www.proginn.com/oauth2/authorize";
}
@Override
public String accessToken() {
return "https://www.proginn.com/oauth2/access_token";
}
@Override
public String userInfo() {
return "https://www.proginn.com/openapi/user/basic_info";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthProginnRequest.class;
}
},
/**
* 爱发电 <a href="https://afdian.net/">爱发电</a>
*/
AFDIAN {
@Override
public String authorize() {
return "https://afdian.net/oauth2/authorize";
}
@Override
public String accessToken() {
return "https://afdian.net/api/oauth2/access_token";
}
@Override
public String userInfo() {
return "";
}
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthProginnRequest.class;
}
}
}
@@ -3,6 +3,7 @@ package me.zhyd.oauth.config;
import me.zhyd.oauth.enums.AuthResponseStatus;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.request.AuthDefaultRequest;
/**
* OAuth平台的API地址的统一接口,提供以下方法:
@@ -73,4 +74,11 @@ public interface AuthSource {
}
return this.getClass().getSimpleName();
}
/**
* 平台对应的 AuthRequest 实现类,必须继承自 {@link AuthDefaultRequest}
*
* @return class
*/
Class<? extends AuthDefaultRequest> getTargetClass();
}
@@ -0,0 +1,34 @@
package me.zhyd.oauth.config;
import me.zhyd.oauth.log.Log;
/**
* JustAuth 日志配置类
*
* @author HeJin
*/
public class JustAuthLogConfig {
/**
* 设置日志级别
*
* @param level 日志级别
*/
public static void setLevel(Log.Level level) {
Log.Config.level = level;
}
/**
* 关闭日志
*/
public static void disable() {
Log.Config.enable = false;
}
/**
* 开启日志
*/
public static void enable() {
Log.Config.enable = true;
}
}
@@ -28,9 +28,10 @@ public enum AuthResponseStatus {
ILLEGAL_CODE(5008, "Illegal code"),
ILLEGAL_STATUS(5009, "Illegal state"),
REQUIRED_REFRESH_TOKEN(5010, "The refresh token is required; it must not be null"),
ILLEGAL_TOKEN(5011, "Invalid token"),
;
private int code;
private String msg;
private final int code;
private final String msg;
}
@@ -0,0 +1,28 @@
package me.zhyd.oauth.enums.scope;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Amazon平台 OAuth 授权范围
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0.0
* @since 1.16.0
*/
@Getter
@AllArgsConstructor
public enum AuthAmazonScope implements AuthScope {
/**
* {@code scope} 含义,以{@code description} 为准
*/
R_LITEPROFILE("profile", "The profile scope includes a user's name and email address", true),
R_EMAILADDRESS("profile:user_id", "The profile:user_id scope only includes the user_id field of the profile", true),
W_MEMBER_SOCIAL("postal_code", "This includes the user's zip/postal code number from their primary shipping address", true);
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -4,7 +4,7 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 度平台 OAuth 授权范围
* 度平台 OAuth 授权范围
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0.0
@@ -23,8 +23,8 @@ public enum AuthBaiduScope implements AuthScope {
PUBLIC("public", "可以访问公共的开放API。", false),
HAO123("hao123", "可以访问Hao123 提供的开放API接口。该权限需要申请开通,请将具体的理由和用途发邮件给tuangou@baidu.com。", false);
private String scope;
private String description;
private boolean isDefault;
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -24,8 +24,8 @@ public enum AuthCodingScope implements AuthScope {
PROJECT_DEPOT("project:depot", "完整的仓库控制权限", false),
PROJECT_WIKI("project:wiki", "授权读取与操作 wiki", false),
;
private String scope;
private String description;
private boolean isDefault;
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -0,0 +1,68 @@
package me.zhyd.oauth.enums.scope;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 抖音平台 OAuth 授权范围
*
* https://open.douyin.com/platform/doc/6855240178122983437
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0.0
* @since 1.16.1
*/
@Getter
@AllArgsConstructor
public enum AuthDouyinScope implements AuthScope {
/**
* 无需申请 默认开启
*/
USER_INFO("user_info", "返回抖音用户公开信息", true),
/**
* 无需申请 默认开启
*/
AWEME_SHARE("aweme.share", "抖音分享", false),
/**
* 普通权限,管理中心申请
*/
IM_SHARE("im.share", "分享给抖音好友", false),
RENEW_REFRESH_TOKEN("renew_refresh_token", "授权有效期动态续期", false),
FOLLOWING_LIST("following.list", "获取该用户的关注列表", false),
FANS_LIST("fans.list", "获取该用户的粉丝列表", false),
VIDEO_CREATE("video.create", "视频发布及管理", false),
VIDEO_DELETE("video.delete", "删除内容", false),
VIDEO_DATA("video.data", "查询授权用户的抖音视频数据", false),
VIDEO_LIST("video.list", "查询特定抖音视频的视频数据", false),
/**
* 特殊权限 默认关闭 管理中心申请
*/
SHARE_WITH_SOURCE("share_with_source", "分享携带来源标签,用户可点击标签进入转化页", false),
MOBILE("mobile", "用抖音帐号登录第三方平台,获得用户在抖音上的手机号码", false),
MOBILE_ALERT("mobile_alert", "用抖音帐号登录第三方平台,获得用户在抖音上的手机号码", false),
VIDEO_SEARCH("video.search", "关键词视频管理", false),
POI_SEARCH("poi.search", "查询POI信息", false),
LOGIN_ID("login_id", "静默授权直接获取该用户的open id", false),
/**
* 抖音数据权限, 默认关闭, 管理中心申请
*/
DATA_EXTERNAL_USER("data.external.user", "查询用户的获赞、评论、分享,主页访问等相关数据", false),
DATA_EXTERNAL_ITEM("data.external.item", "查询作品的获赞,评论,分享等相关数据", false),
FANS_DATA("fans.data", "获取用户粉丝画像数据", false),
HOTSEARCH("hotsearch", "获取抖音热门内容", false),
STAR_TOP_SCORE_DISPLAY("star_top_score_display", "星图达人与达人对应各指数评估分,以及星图6大热门维度下的达人榜单", false),
STAR_TOPS("star_tops", "星图达人与达人对应各指数评估分,以及星图6大热门维度下的达人榜单", false),
STAR_AUTHOR_SCORE_DISPLAY("star_author_score_display", "星图达人与达人对应各指数评估分,以及星图6大热门维度下的达人榜单", false),
notes("data.external.sdk_share", "获取用户通过分享SDK分享视频数据", false),
/**
* 定向开通 默认关闭 定向开通
*/
DISCOVERY_ENT("discovery.ent", "查询抖音电影榜、抖音剧集榜、抖音综艺榜数据", false),
;
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -17,6 +17,7 @@ public enum AuthFacebookScope implements AuthScope {
/**
* {@code scope} 含义,以{@code description} 为准
*/
PUBLIC_PROFILE("public_profile", "权限允许应用读取用户默认的公开资料", true),
EMAIL("email", "获取用户的邮箱", false),
USER_AGE_RANGE("user_age_range", "允许应用程序访问用户的年龄范围", false),
USER_BIRTHDAY("user_birthday", "获取用户的生日", false),
@@ -24,7 +25,7 @@ public enum AuthFacebookScope implements AuthScope {
USER_GENDER("user_gender", "获取用户的性别", false),
USER_HOMETOWN("user_hometown", "获取用户的家乡信息", false),
USER_LIKES("user_likes", "获取用户的喜欢列表", false),
USER_LINK("user_link", "获取用户的个人链接", false),
USER_LINK("user_link", "获取用户的个人链接", true),
USER_LOCATION("user_location", "获取用户的位置信息", false),
USER_PHOTOS("user_photos", "获取用户的相册信息", false),
USER_POSTS("user_posts", "获取用户发布的内容", false),
@@ -33,8 +34,8 @@ public enum AuthFacebookScope implements AuthScope {
PUBLISH_TO_GROUPS("publish_to_groups", "授权您的应用程序代表某人将内容发布到组中,前提是他们已经授予您的应用程序访问权限", false),
;
private String scope;
private String description;
private boolean isDefault;
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -29,8 +29,8 @@ public enum AuthGiteeScope implements AuthScope {
ENTERPRISES("enterprises", "查看、管理用户的企业以及成员", false),
EMAILS("emails", "查看用户的个人邮箱信息", false);
private String scope;
private String description;
private boolean isDefault;
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -4,7 +4,7 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 边度平台 OAuth 授权范围
* Github平台 OAuth 授权范围
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0.0
@@ -47,8 +47,8 @@ public enum AuthGithubScope implements AuthScope {
READ_GPG_KEY("read:gpg_key", "List and view details for GPG keys.", false),
WORKFLOW("workflow", "Grants the ability to add and update GitHub Actions workflow files. Workflow files can be committed without this scope if the same file (with both the same path and contents) exists on another branch in the same repository.", false),
;
private String scope;
private String description;
private boolean isDefault;
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -30,8 +30,8 @@ public enum AuthGitlabScope implements AuthScope {
API("api", "Grants complete read/write access to the API, including all groups and projects, the container registry, and the package registry.", false),
;
private String scope;
private String description;
private boolean isDefault;
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -281,9 +281,9 @@ public enum AuthGoogleScope implements AuthScope {
ADEXCHANGE_BUYER("https://www.googleapis.com/auth/adexchange.buyer", "Manage your Ad Exchange buyer account configuration", false),
;
private String scope;
private String description;
private boolean isDefault;
private final String scope;
private final String description;
private final boolean isDefault;
public static List<String> getAdminDirectoryScopes() {
@@ -39,8 +39,8 @@ public enum AuthHuaweiScope implements AuthScope {
;
private String scope;
private String description;
private boolean isDefault;
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -19,8 +19,8 @@ public enum AuthJdScope implements AuthScope {
*/
SNSAPI_BASE("snsapi_base", "基础授权", true);
private String scope;
private String description;
private boolean isDefault;
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -21,8 +21,8 @@ public enum AuthKujialeScope implements AuthScope {
GET_DESIGN("get_design", "获取指定方案详情", false),
GET_BUDGET_LIST("get_budget_list", "获取清单预算概览数据", false);
private String scope;
private String description;
private boolean isDefault;
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -0,0 +1,28 @@
package me.zhyd.oauth.enums.scope;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Line 平台 OAuth 授权范围
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @since 1.16.0
*/
@Getter
@AllArgsConstructor
public enum AuthLineScope implements AuthScope {
/**
* {@code scope} 含义,以{@code description} 为准
*/
PROFILE("profile", "Get profile details", true),
OPENID("openid", "Get id token", true),
EMAIL("email", "Get email (separate authorization required)", false);
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -36,8 +36,8 @@ public enum AuthLinkedinScope implements AuthScope {
W_ORGANIZATION_SOCIAL("w_organization_social", "Post, comment and like posts on your organization's behalf", false),
W_SHARE("w_share", "Post updates to LinkedIn as you", false);
private String scope;
private String description;
private boolean isDefault;
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -21,8 +21,8 @@ public enum AuthMiScope implements AuthScope {
OPENID("user/openIdV2", "获取用户的OpenID", true),
PHONE_EMAIL("user/phoneAndEmail", "获取用户的手机号和邮箱", true);
private String scope;
private String description;
private boolean isDefault;
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -60,8 +60,8 @@ public enum AuthMicrosoftScope implements AuthScope {
NOTES_READWRITE_ALL("Notes.ReadWrite.All", "允许应用读取、共享和修改已登录用户在组织中有权访问的 OneNote 笔记本", false),
;
private String scope;
private String description;
private boolean isDefault;
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -0,0 +1,66 @@
package me.zhyd.oauth.enums.scope;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Okta 平台 OAuth 授权范围
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @since 1.16.0
*/
@Getter
@AllArgsConstructor
public enum AuthOktaScope implements AuthScope {
/**
* {@code scope} 含义,以{@code description} 为准
*/
OPENID("openid", "Signals that a request is an OpenID request.", true),
PROFILE("profile", "The exact data varies based on what profile information you have provided, such as: name, time zone, picture, or birthday.", true),
EMAIL("email", "This allows the app to view your email address.", true),
ADDRESS("address", "This allows the app to view your address, such as: street address, city, state, and zip code.", true),
PHONE("phone", "This allows the app to view your phone number.", true),
OFFLINE_ACCESS("offline_access", "This keeps you signed in to the app, even when you are not using it.", true),
OKTA_USERS_MANAGE("okta.users.manage", "Allows the app to create and manage users and read all profile and credential information for users", false),
OKTA_USERS_READ("okta.users.read", "Allows the app to read any user's profile and credential information", false),
OKTA_USERS_MANAGE_SELF("okta.users.manage.self", "Allows the app to manage the currently signed-in user's profile. Currently only supports user profile attribute updates.", false),
OKTA_USERS_READ_SELF("okta.users.read.self", "Allows the app to read the currently signed-in user's profile and credential information", false),
OKTA_APPS_MANAGE("okta.apps.manage", "Allows the app to create and manage Apps in your Okta organization", false),
OKTA_APPS_READ("okta.apps.read", "Allows the app to read information about Apps in your Okta organization", false),
OKTA_AUTHORIZATIONSERVERS_MANAGE("okta.authorizationServers.manage", "Allows the app to manage authorization servers", false),
OKTA_AUTHORIZATIONSERVERS_READ("okta.authorizationServers.read", "Allows the app to read authorization server information", false),
OKTA_CLIENTS_MANAGE("okta.clients.manage", "Allows the app to manage all OAuth/OIDC clients and to create new clients", false),
OKTA_CLIENTS_READ("okta.clients.read", "Allows the app to read information for all OAuth/OIDC clients", false),
OKTA_CLIENTS_REGISTER("okta.clients.register", "Allows the app to register (create) new OAuth/OIDC clients (but not read information about existing clients)", false),
OKTA_EVENTHOOKS_MANAGE("okta.eventHooks.manage", "Allows the app to create and manage Event Hooks in your Okta organization", false),
OKTA_EVENTHOOKS_READ("okta.eventHooks.read", "Allows the app to read information about Event Hooks in your Okta organization", false),
OKTA_FACTORS_MANAGE("okta.factors.manage", "Allows the app to manage all admin operations for org factors (for example, activate, deactive, read)", false),
OKTA_FACTORS_READ("okta.factors.read", "Allows the app to read org factors information", false),
OKTA_GROUPS_MANAGE("okta.groups.manage", "Allows the app to manage groups in your Okta organization", false),
OKTA_GROUPS_READ("okta.groups.read", "Allows the app to read information about groups and their members in your Okta organization", false),
OKTA_IDPS_MANAGE("okta.idps.manage", "Allows the app to create and manage Identity Providers in your Okta organization", false),
OKTA_IDPS_READ("okta.idps.read", "Allows the app to read information about Identity Providers in your Okta organization", false),
OKTA_INLINEHOOKS_MANAGE("okta.inlineHooks.manage", "Allows the app to create and manage Inline Hooks in your Okta organization.", false),
OKTA_INLINEHOOKS_READ("okta.inlineHooks.read", "Allows the app to read information about Inline Hooks in your Okta organization.", false),
OKTA_LINKEDOBJECTS_MANAGE("okta.linkedObjects.manage", "Allows the app to manage Linked Object definitions in your Okta organization.", false),
OKTA_LINKEDOBJECTS_READ("okta.linkedObjects.read", "Allows the app to read Linked Object definitions in your Okta organization.", false),
OKTA_LOGS_READ("okta.logs.read", "Allows the app to read information about System Log entries in your Okta organization", false),
OKTA_ROLES_MANAGE("okta.roles.manage", "Allows the app to create and manage Administrator Roles in your Okta organization", false),
OKTA_ROLES_READ("okta.roles.read", "Allows the app to read information about Administrator Roles in your Okta organization", false),
OKTA_SCHEMAS_MANAGE("okta.schemas.manage", "Allows the app to create and manage Schemas in your Okta organization", false),
OKTA_SCHEMAS_READ("okta.schemas.read", "Allows the app to read information about Schemas in your Okta organization", false),
OKTA_SESSIONS_MANAGE("okta.sessions.manage", "Allows the app to manage all sessions in your Okta organization", false),
OKTA_SESSIONS_READ("okta.sessions.read", "Allows the app to read all sessions in your Okta organization", false),
OKTA_TEMPLATES_MANAGE("okta.templates.manage", "Allows the app to manage all custom templates in your Okta organization", false),
OKTA_TEMPLATES_READ("okta.templates.read", "Allows the app to read all custom templates in your Okta organization", false),
OKTA_TRUSTEDORIGINS_MANAGE("okta.trustedOrigins.manage", "Allows the app to manage all Trusted Origins in your Okta organization", false),
OKTA_TRUSTEDORIGINS_READ("okta.trustedOrigins.read", "Allows the app to read all Trusted Origins in your Okta organization", false),
OKTA_POLICIES_MANAGE("okta.policies.manage", "Allows the app to manage Policies in your Okta organization", false),
OKTA_POLICIES_READ("okta.policies.read", "Allows the app to read information about Policies in your Okta organization", false),;
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -23,8 +23,8 @@ public enum AuthPinterestScope implements AuthScope {
WRITE_RELATIONSHIPS("write_relationships", "Use PATCH, POST and DELETE methods on a users follows and followers (on boards, users and interests).", false),
;
private String scope;
private String description;
private boolean isDefault;
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -0,0 +1,33 @@
package me.zhyd.oauth.enums.scope;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Gitee 平台 OAuth 授权范围
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @version 1.0.0
* @since 1.0.0
*/
@Getter
@AllArgsConstructor
public enum AuthProginnScope implements AuthScope {
/**
* {@code scope} 含义,以{@code description} 为准
*/
BASIC("basic", "访问用户的基本信息", true),
/**
* 以上 scope 需要单独向程序员客栈平台申请,否则不可使用
*/
email("email", "获取用户的邮箱", false),
realname("realname", "获取用户的真实姓名", false),
cellphone("cellphone", "获取用户的手机号码", false),
;
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -28,8 +28,8 @@ public enum AuthQqScope implements AuthScope {
ADD_ALBUM("add_album", "在用户的空间相册里,创建一个新的个人相册", false),
LIST_PHOTO("list_photo", "获取用户QQ空间相册中的照片列表", false);
private String scope;
private String description;
private boolean isDefault;
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -48,8 +48,8 @@ public enum AuthRenrenScope implements AuthScope {
ADMIN_PAGE("admin_page", "以用户的身份,管理其可以管理的公共主页的权限。", false),
;
private String scope;
private String description;
private boolean isDefault;
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -0,0 +1,116 @@
package me.zhyd.oauth.enums.scope;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Slack 平台 OAuth 授权范围
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @since 1.16.0
*/
@Getter
@AllArgsConstructor
public enum AuthSlackScope implements AuthScope {
/**
* {@code scope} 含义,以{@code description} 为准
*/
USERS_PROFILE_READ("users.profile:read", "View profile details about people in a workspace", true),
USERS_READ("users:read", "View people in a workspace", true),
USERS_READ_EMAIL("users:read.email", "View email addresses of people in a workspace", true),
USERS_PROFILE_WRITE("users.profile:write", "Edit a users profile information and status", false),
USERS_PROFILE_WRITE_USER("users.profile:write:user", "Change the user's profile fields", false),
USERS_WRITE("users:write", "Set presence for your slack app", false),
ADMIN("admin", "Administer a workspace", false),
ADMIN_ANALYTICS_READ("admin.analytics:read", "Access analytics data about the organization", false),
ADMIN_APPS_READ("admin.apps:read", "View apps and app requests in a workspace", false),
ADMIN_APPS_WRITE("admin.apps:write", "Manage apps in a workspace", false),
ADMIN_BARRIERS_READ("admin.barriers:read", "Read information barriers in the organization", false),
ADMIN_BARRIERS_WRITE("admin.barriers:write", "Manage information barriers in the organization", false),
ADMIN_CONVERSATIONS_READ("admin.conversations:read", "View the channels member list, topic, purpose and channel name", false),
ADMIN_CONVERSATIONS_WRITE("admin.conversations:write", "Start a new conversation, modify a conversation and modify channel details", false),
ADMIN_INVITES_READ("admin.invites:read", "Gain information about invite requests in a Grid organization.", false),
ADMIN_INVITES_WRITE("admin.invites:write", "Approve or deny invite requests in a Grid organization.", false),
ADMIN_TEAMS_READ("admin.teams:read", "Access information about a workspace", false),
ADMIN_TEAMS_WRITE("admin.teams:write", "Make changes to a workspace", false),
ADMIN_USERGROUPS_READ("admin.usergroups:read", "Access information about user groups", false),
ADMIN_USERGROUPS_WRITE("admin.usergroups:write", "Make changes to your usergroups", false),
ADMIN_USERS_READ("admin.users:read", "Access a workspaces profile information", false),
ADMIN_USERS_WRITE("admin.users:write", "Modify account information", false),
APP_MENTIONS_READ("app_mentions:read", "View messages that directly mention @your_slack_app in conversations that the app is in", false),
AUDITLOGS_READ("auditlogs:read", "View events from all workspaces, channels and users (Enterprise Grid only)", false),
BOT("bot", "Add the ability for people to direct message or mention @your_slack_app", false),
CALLS_READ("calls:read", "View information about ongoing and past calls", false),
CALLS_WRITE("calls:write", "Start and manage calls in a workspace", false),
CHANNELS_HISTORY("channels:history", "View messages and other content in public channels that your slack app has been added to", false),
CHANNELS_JOIN("channels:join", "Join public channels in a workspace", false),
CHANNELS_MANAGE("channels:manage", "Manage public channels that your slack app has been added to and create new ones", false),
CHANNELS_READ("channels:read", "View basic information about public channels in a workspace", false),
CHANNELS_WRITE("channels:write", "Manage a users public channels and create new ones on a users behalf", false),
CHAT_WRITE("chat:write", "Post messages in approved channels & conversations", false),
CHAT_WRITE_CUSTOMIZE("chat:write.customize", "Send messages as @your_slack_app with a customized username and avatar", false),
CHAT_WRITE_PUBLIC("chat:write.public", "Send messages to channels @your_slack_app isn't a member of", false),
CHAT_WRITE_BOT("chat:write:bot", "Send messages as your slack app", false),
CHAT_WRITE_USER("chat:write:user", "Send messages on a users behalf", false),
CLIENT("client", "Receive all events from a workspace in real time", false),
COMMANDS("commands", "Add shortcuts and/or slash commands that people can use", false),
CONVERSATIONS_HISTORY("conversations:history", "Deprecated: Retrieve conversation history for legacy workspace apps", false),
CONVERSATIONS_READ("conversations:read", "Deprecated: Retrieve information on conversations for legacy workspace apps", false),
CONVERSATIONS_WRITE("conversations:write", "Deprecated: Edit conversation attributes for legacy workspace apps", false),
DND_READ("dnd:read", "View Do Not Disturb settings for people in a workspace", false),
DND_WRITE("dnd:write", "Edit a users Do Not Disturb settings", false),
DND_WRITE_USER("dnd:write:user", "Change the user's Do Not Disturb settings", false),
EMOJI_READ("emoji:read", "View custom emoji in a workspace", false),
FILES_READ("files:read", "View files shared in channels and conversations that your slack app has been added to", false),
FILES_WRITE("files:write", "Upload, edit, and delete files as your slack app", false),
FILES_WRITE_USER("files:write:user", "Upload, edit, and delete files as your slack app", false),
GROUPS_HISTORY("groups:history", "View messages and other content in private channels that your slack app has been added to", false),
GROUPS_READ("groups:read", "View basic information about private channels that your slack app has been added to", false),
GROUPS_WRITE("groups:write", "Manage private channels that your slack app has been added to and create new ones", false),
IDENTIFY("identify", "View information about a users identity", false),
IDENTITY_AVATAR("identity.avatar", "View a users Slack avatar", false),
IDENTITY_AVATAR_READ_USER("identity.avatar:read:user", "View the user's profile picture", false),
IDENTITY_BASIC("identity.basic", "View information about a users identity", false),
IDENTITY_EMAIL("identity.email", "View a users email address", false),
IDENTITY_EMAIL_READ_USER("identity.email:read:user", "This scope is not yet described.", false),
IDENTITY_TEAM("identity.team", "View a users Slack workspace name", false),
IDENTITY_TEAM_READ_USER("identity.team:read:user", "View the workspace's name, domain, and icon", false),
IDENTITY_READ_USER("identity:read:user", "This scope is not yet described.", false),
IM_HISTORY("im:history", "View messages and other content in direct messages that your slack app has been added to", false),
IM_READ("im:read", "View basic information about direct messages that your slack app has been added to", false),
IM_WRITE("im:write", "Start direct messages with people", false),
INCOMING_WEBHOOK("incoming-webhook", "Create one-way webhooks to post messages to a specific channel", false),
LINKS_READ("links:read", "View URLs in messages", false),
LINKS_WRITE("links:write", "Show previews of URLs in messages", false),
MPIM_HISTORY("mpim:history", "View messages and other content in group direct messages that your slack app has been added to", false),
MPIM_READ("mpim:read", "View basic information about group direct messages that your slack app has been added to", false),
MPIM_WRITE("mpim:write", "Start group direct messages with people", false),
NONE("none", "Execute methods without needing a scope", false),
PINS_READ("pins:read", "View pinned content in channels and conversations that your slack app has been added to", false),
PINS_WRITE("pins:write", "Add and remove pinned messages and files", false),
POST("post", "Post messages to a workspace", false),
REACTIONS_READ("reactions:read", "View emoji reactions and their associated content in channels and conversations that your slack app has been added to", false),
REACTIONS_WRITE("reactions:write", "Add and edit emoji reactions", false),
READ("read", "View all content in a workspace", false),
REMINDERS_READ("reminders:read", "View reminders created by your slack app", false),
REMINDERS_READ_USER("reminders:read:user", "Access reminders created by a user or for a user", false),
REMINDERS_WRITE("reminders:write", "Add, remove, or mark reminders as complete", false),
REMINDERS_WRITE_USER("reminders:write:user", "Add, remove, or complete reminders for the user", false),
REMOTE_FILES_READ("remote_files:read", "View remote files added by the app in a workspace", false),
REMOTE_FILES_SHARE("remote_files:share", "Share remote files on a users behalf", false),
REMOTE_FILES_WRITE("remote_files:write", "Add, edit, and delete remote files on a users behalf", false),
SEARCH_READ("search:read", "Search a workspaces content", false),
STARS_READ("stars:read", "View messages and files that your slack app has starred", false),
STARS_WRITE("stars:write", "Add or remove stars", false),
TEAM_READ("team:read", "View the name, email domain, and icon for workspaces your slack app is connected to", false),
TOKENS_BASIC("tokens.basic", "Execute methods without needing a scope", false),
USERGROUPS_READ("usergroups:read", "View user groups in a workspace", false),
USERGROUPS_WRITE("usergroups:write", "Create and manage user groups", false),
WORKFLOW_STEPS_EXECUTE("workflow.steps:execute", "Add steps that people can use in Workflow Builder", false);
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -22,8 +22,8 @@ public enum AuthStackoverflowScope implements AuthScope {
WRITE_ACCESS("write_access", "perform write operations as a user", false),
PRIVATE_INFO("private_info", "access full history of a user's private actions on the site", false);
private String scope;
private String description;
private boolean isDefault;
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -0,0 +1,24 @@
package me.zhyd.oauth.enums.scope;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 企业自建应用授权范围
*
* @author liguanhua (347826496(a)qq.com)
* @since 1.15.9
*/
@Getter
@AllArgsConstructor
public enum AuthWeChatEnterpriseWebScope implements AuthScope {
/**
* {@code scope} 含义,以{@code description} 为准
*/
SNSAPI_BASE("snsapi_base", "应用授权作用域。企业自建应用固定填写:snsapi_base", true);
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -19,8 +19,8 @@ public enum AuthWechatMpScope implements AuthScope {
SNSAPI_USERINFO("snsapi_userinfo", "弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息", true),
SNSAPI_BASE("snsapi_base", "不弹出授权页面,直接跳转,只能获取用户openid", false);
private String scope;
private String description;
private boolean isDefault;
private final String scope;
private final String description;
private final boolean isDefault;
}
@@ -27,8 +27,8 @@ public enum AuthWeiboScope implements AuthScope {
STATUSES_TO_ME_READ("statuses_to_me_read", "定向微博读取接口组,<a rel=\"nofollow\" href=\"http://open.weibo.com/wiki/API%E6%96%87%E6%A1%A3_V2#.E5.BE.AE.E5.8D.9A\">接口文档</a>", false),
FOLLOW_APP_OFFICIAL_MICROBLOG("follow_app_official_microblog", "关注应用官方微博,该参数不对应具体接口,只需在应用控制台填写官方帐号即可。填写的路径:我的应用-选择自己的应用-应用信息-基本信息-官方运营账号(默认值是应用开发者帐号)", false);
private String scope;
private String description;
private boolean isDefault;
private final String scope;
private final String description;
private final boolean isDefault;
}
+3 -3
View File
@@ -136,15 +136,15 @@ public class Log {
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @since 1.10.0
*/
static class Config {
public static class Config {
/**
* 需要打印的日志级别
*/
static Level level = Level.DEBUG;
public static Level level = Level.DEBUG;
/**
* 是否启用日志打印功能,默认启用
*/
static boolean enable = true;
public static boolean enable = true;
}
}
@@ -1,4 +1,4 @@
/**
* 针对JustAuth简单封装的日志打印工具,可用过{@link me.zhyd.oauth.log.Log.Config}开关日志和指定日志级别
* 针对JustAuth简单封装的日志打印工具,可用过{@link me.zhyd.oauth.config.JustAuthLogConfig}开关日志和指定日志级别
*/
package me.zhyd.oauth.log;
@@ -19,6 +19,7 @@ public class AuthToken implements Serializable {
private String accessToken;
private int expireIn;
private String refreshToken;
private int refreshTokenExpireIn;
private String uid;
private String openId;
private String accessCode;
@@ -43,6 +44,12 @@ public class AuthToken implements Serializable {
* @since 1.10.0
*/
private String code;
/**
* 微信公众号 - 网页授权的登录时可用
*
* 微信针对网页授权登录,增加了一个快照页的逻辑,快照页获取到的微信用户的 uid oid 和头像昵称都是虚拟的信息
*/
private boolean snapshotUser;
/**
* Twitter附带属性
@@ -72,4 +72,11 @@ public class AuthUser implements Serializable {
*/
private JSONObject rawUserInfo;
/**
* 微信公众号 - 网页授权的登录时可用
*
* 微信针对网页授权登录,增加了一个快照页的逻辑,快照页获取到的微信用户的 uid oid 和头像昵称都是虚拟的信息
*/
private boolean snapshotUser;
}
@@ -0,0 +1,104 @@
package me.zhyd.oauth.request;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.config.AuthSource;
import me.zhyd.oauth.enums.AuthUserGender;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.utils.GlobalAuthUtils;
import me.zhyd.oauth.utils.HttpUtils;
import me.zhyd.oauth.utils.UrlBuilder;
/**
* <p>
* 钉钉登录抽象类,负责处理使用钉钉账号登录第三方网站和扫码登录第三方网站两种钉钉的登录方式
* </p>
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @since 1.16.0
*/
public abstract class AbstractAuthDingtalkRequest extends AuthDefaultRequest {
public AbstractAuthDingtalkRequest(AuthConfig config, AuthSource source) {
super(config, source);
}
public AbstractAuthDingtalkRequest(AuthConfig config, AuthSource source, AuthStateCache authStateCache) {
super(config, source, authStateCache);
}
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
return AuthToken.builder().accessCode(authCallback.getCode()).build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String code = authToken.getAccessCode();
JSONObject param = new JSONObject();
param.put("tmp_auth_code", code);
String response = new HttpUtils(config.getHttpConfig()).post(userInfoUrl(authToken), param.toJSONString()).getBody();
JSONObject object = JSON.parseObject(response);
if (object.getIntValue("errcode") != 0) {
throw new AuthException(object.getString("errmsg"));
}
object = object.getJSONObject("user_info");
AuthToken token = AuthToken.builder()
.openId(object.getString("openid"))
.unionId(object.getString("unionid"))
.build();
return AuthUser.builder()
.rawUserInfo(object)
.uuid(object.getString("unionid"))
.nickname(object.getString("nick"))
.username(object.getString("nick"))
.gender(AuthUserGender.UNKNOWN)
.source(source.toString())
.token(token)
.build();
}
/**
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public String authorize(String state) {
return UrlBuilder.fromBaseUrl(source.authorize())
.queryParam("response_type", "code")
.queryParam("appid", config.getClientId())
.queryParam("scope", "snsapi_login")
.queryParam("redirect_uri", config.getRedirectUri())
.queryParam("state", getRealState(state))
.build();
}
/**
* 返回获取userInfo的url
*
* @param authToken 用户授权后的token
* @return 返回获取userInfo的url
*/
@Override
protected String userInfoUrl(AuthToken authToken) {
// 根据timestamp, appSecret计算签名值
String timestamp = System.currentTimeMillis() + "";
String urlEncodeSignature = GlobalAuthUtils.generateDingTalkSignature(config.getClientSecret(), timestamp);
return UrlBuilder.fromBaseUrl(source.userInfo())
.queryParam("signature", urlEncodeSignature)
.queryParam("timestamp", timestamp)
.queryParam("accessKey", config.getClientId())
.build();
}
}
@@ -0,0 +1,191 @@
package me.zhyd.oauth.request;
import com.alibaba.fastjson.JSONObject;
import com.xkcoding.http.support.HttpHeader;
import com.xkcoding.http.util.MapUtil;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.config.AuthSource;
import me.zhyd.oauth.enums.AuthResponseStatus;
import me.zhyd.oauth.enums.AuthUserGender;
import me.zhyd.oauth.enums.scope.AuthMicrosoftScope;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.utils.AuthScopeUtils;
import me.zhyd.oauth.utils.HttpUtils;
import me.zhyd.oauth.utils.StringUtils;
import me.zhyd.oauth.utils.UrlBuilder;
import java.util.Map;
/**
* 微软登录抽象类,负责处理使用微软国际和微软中国账号登录第三方网站的登录方式
*
* @author mroldx (xzfqq5201314@gmail.com)
* @since 1.16.4
*/
public abstract class AbstractAuthMicrosoftRequest extends AuthDefaultRequest {
public AbstractAuthMicrosoftRequest(AuthConfig config, AuthSource source) {
super(config, source);
}
public AbstractAuthMicrosoftRequest(AuthConfig config, AuthSource source, AuthStateCache authStateCache) {
super(config, source, authStateCache);
}
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
return getToken(accessTokenUrl(authCallback.getCode()));
}
/**
* 获取token,适用于获取access_token和刷新token
*
* @param accessTokenUrl 实际请求token的地址
* @return token对象
*/
private AuthToken getToken(String accessTokenUrl) {
HttpHeader httpHeader = new HttpHeader();
Map<String, String> form = MapUtil.parseStringToMap(accessTokenUrl, false);
String response = new HttpUtils(config.getHttpConfig()).post(accessTokenUrl, form, httpHeader, false).getBody();
JSONObject accessTokenObject = JSONObject.parseObject(response);
this.checkResponse(accessTokenObject);
return AuthToken.builder()
.accessToken(accessTokenObject.getString("access_token"))
.expireIn(accessTokenObject.getIntValue("expires_in"))
.scope(accessTokenObject.getString("scope"))
.tokenType(accessTokenObject.getString("token_type"))
.refreshToken(accessTokenObject.getString("refresh_token"))
.build();
}
/**
* 检查响应内容是否正确
*
* @param object 请求响应内容
*/
private void checkResponse(JSONObject object) {
if (object.containsKey("error")) {
throw new AuthException(object.getString("error_description"));
}
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String token = authToken.getAccessToken();
String tokenType = authToken.getTokenType();
String jwt = tokenType + " " + token;
HttpHeader httpHeader = new HttpHeader();
httpHeader.add("Authorization", jwt);
String userInfo = new HttpUtils(config.getHttpConfig()).get(userInfoUrl(authToken), null, httpHeader, false).getBody();
JSONObject object = JSONObject.parseObject(userInfo);
this.checkResponse(object);
return AuthUser.builder()
.rawUserInfo(object)
.uuid(object.getString("id"))
.username(object.getString("userPrincipalName"))
.nickname(object.getString("displayName"))
.location(object.getString("officeLocation"))
.email(object.getString("mail"))
.gender(AuthUserGender.UNKNOWN)
.token(authToken)
.source(source.toString())
.build();
}
/**
* 刷新access token (续期)
*
* @param authToken 登录成功后返回的Token信息
* @return AuthResponse
*/
@Override
public AuthResponse refresh(AuthToken authToken) {
return AuthResponse.builder()
.code(AuthResponseStatus.SUCCESS.getCode())
.data(getToken(refreshTokenUrl(authToken.getRefreshToken())))
.build();
}
/**
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public String authorize(String state) {
// 兼容 Microsoft Entra ID 登录(原微软 AAD
// @since 1.16.6
String tenantId = StringUtils.isEmpty(config.getTenantId()) ? "common" : config.getTenantId();
return UrlBuilder.fromBaseUrl(String.format(source.authorize(), tenantId))
.queryParam("response_type", "code")
.queryParam("client_id", config.getClientId())
.queryParam("redirect_uri", config.getRedirectUri())
.queryParam("state", getRealState(state))
.queryParam("response_mode", "query")
.queryParam("scope", this.getScopes(" ", false, AuthScopeUtils.getDefaultScopes(AuthMicrosoftScope.values())))
.build();
}
/**
* 返回获取accessToken的url
*
* @param code 授权code
* @return 返回获取accessToken的url
*/
@Override
protected String accessTokenUrl(String code) {
String tenantId = StringUtils.isEmpty(config.getTenantId()) ? "common" : config.getTenantId();
return UrlBuilder.fromBaseUrl(String.format(source.accessToken(), tenantId))
.queryParam("code", code)
.queryParam("client_id", config.getClientId())
.queryParam("client_secret", config.getClientSecret())
.queryParam("grant_type", "authorization_code")
.queryParam("scope", this.getScopes(" ", false, AuthScopeUtils.getDefaultScopes(AuthMicrosoftScope.values())))
.queryParam("redirect_uri", config.getRedirectUri())
.build();
}
/**
* 返回获取userInfo的url
*
* @param authToken 用户授权后的token
* @return 返回获取userInfo的url
*/
@Override
protected String userInfoUrl(AuthToken authToken) {
return UrlBuilder.fromBaseUrl(source.userInfo()).build();
}
/**
* 返回获取accessToken的url
*
* @param refreshToken 用户授权后的token
* @return 返回获取accessToken的url
*/
@Override
protected String refreshTokenUrl(String refreshToken) {
String tenantId = StringUtils.isEmpty(config.getTenantId()) ? "common" : config.getTenantId();
return UrlBuilder.fromBaseUrl(String.format(source.refresh(), tenantId))
.queryParam("client_id", config.getClientId())
.queryParam("client_secret", config.getClientSecret())
.queryParam("refresh_token", refreshToken)
.queryParam("grant_type", "refresh_token")
.queryParam("scope", this.getScopes(" ", false, AuthScopeUtils.getDefaultScopes(AuthMicrosoftScope.values())))
.queryParam("redirect_uri", config.getRedirectUri())
.build();
}
}
@@ -1,44 +1,41 @@
package me.zhyd.oauth.request;
import com.alibaba.fastjson.JSONObject;
import me.zhyd.oauth.utils.HttpUtils;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.config.AuthDefaultSource;
import me.zhyd.oauth.config.AuthSource;
import me.zhyd.oauth.enums.AuthResponseStatus;
import me.zhyd.oauth.enums.AuthUserGender;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.utils.HttpUtils;
import me.zhyd.oauth.utils.StringUtils;
import me.zhyd.oauth.utils.UrlBuilder;
/**
* <p>
* 企业微信登录
* 企业微信登录父类
* </p>
*
* @author yangkai.shen (https://xkcoding.com)
* @since 1.10.0
* @author liguanhua (347826496(a)qq.com)
* @since 1.15.9
*/
public class AuthWeChatEnterpriseRequest extends AuthDefaultRequest {
public AuthWeChatEnterpriseRequest(AuthConfig config) {
super(config, AuthDefaultSource.WECHAT_ENTERPRISE);
public abstract class AbstractAuthWeChatEnterpriseRequest extends AuthDefaultRequest {
public AbstractAuthWeChatEnterpriseRequest(AuthConfig config, AuthSource source) {
super(config,source);
}
public AuthWeChatEnterpriseRequest(AuthConfig config, AuthStateCache authStateCache) {
super(config, AuthDefaultSource.WECHAT_ENTERPRISE, authStateCache);
public AbstractAuthWeChatEnterpriseRequest(AuthConfig config, AuthSource source, AuthStateCache authStateCache) {
super(config, source, authStateCache);
}
/**
* 微信的特殊性此时返回的信息同时包含 openid access_token
*
* @param authCallback 回调返回的参数
* @return 所有信息
*/
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
String response = doGetAuthorizationCode(accessTokenUrl(authCallback.getCode()));
String response = doGetAuthorizationCode(accessTokenUrl(null));
JSONObject object = this.checkResponse(response);
@@ -59,8 +56,8 @@ public class AuthWeChatEnterpriseRequest extends AuthDefaultRequest {
throw new AuthException(AuthResponseStatus.UNIDENTIFIED_PLATFORM, source);
}
String userId = object.getString("UserId");
String userDetailResponse = getUserDetail(authToken.getAccessToken(), userId);
JSONObject userDetail = this.checkResponse(userDetailResponse);
String userTicket = object.getString("user_ticket");
JSONObject userDetail = getUserDetail(authToken.getAccessToken(), userId, userTicket);
return AuthUser.builder()
.rawUserInfo(userDetail)
@@ -92,22 +89,6 @@ public class AuthWeChatEnterpriseRequest extends AuthDefaultRequest {
return object;
}
/**
* 返回带{@code state}参数的授权url授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public String authorize(String state) {
return UrlBuilder.fromBaseUrl(source.authorize())
.queryParam("appid", config.getClientId())
.queryParam("agentid", config.getAgentId())
.queryParam("redirect_uri", config.getRedirectUri())
.queryParam("state", getRealState(state))
.build();
}
/**
* 返回获取accessToken的url
@@ -142,14 +123,31 @@ public class AuthWeChatEnterpriseRequest extends AuthDefaultRequest {
*
* @param accessToken accessToken
* @param userId 企业内用户id
* @param userTicket 成员票据用于获取用户信息或敏感信息
* @return 用户详情
*/
private String getUserDetail(String accessToken, String userId) {
String userDetailUrl = UrlBuilder.fromBaseUrl("https://qyapi.weixin.qq.com/cgi-bin/user/get")
private JSONObject getUserDetail(String accessToken, String userId, String userTicket) {
// 用户基础信息
String userInfoUrl = UrlBuilder.fromBaseUrl("https://qyapi.weixin.qq.com/cgi-bin/user/get")
.queryParam("access_token", accessToken)
.queryParam("userid", userId)
.build();
return new HttpUtils(config.getHttpConfig()).get(userDetailUrl);
String userInfoResponse = new HttpUtils(config.getHttpConfig()).get(userInfoUrl).getBody();
JSONObject userInfo = checkResponse(userInfoResponse);
// 用户敏感信息
if (StringUtils.isNotEmpty(userTicket)) {
String userDetailUrl = UrlBuilder.fromBaseUrl("https://qyapi.weixin.qq.com/cgi-bin/auth/getuserdetail")
.queryParam("access_token", accessToken)
.build();
JSONObject param = new JSONObject();
param.put("user_ticket", userTicket);
String userDetailResponse = new HttpUtils(config.getHttpConfig()).post(userDetailUrl, param.toJSONString()).getBody();
JSONObject userDetail = checkResponse(userDetailResponse);
userInfo.putAll(userDetail);
}
return userInfo;
}
}
@@ -0,0 +1,73 @@
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.model.AuthCallback;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.utils.HttpUtils;
import me.zhyd.oauth.utils.UrlBuilder;
import java.util.HashMap;
import java.util.Map;
/**
* 爱发电
*
* @author handy
*/
public class AuthAfDianRequest extends AuthDefaultRequest {
public AuthAfDianRequest(AuthConfig config) {
super(config, AuthDefaultSource.AFDIAN);
}
public AuthAfDianRequest(AuthConfig config, AuthStateCache authStateCache) {
super(config, AuthDefaultSource.AFDIAN, authStateCache);
}
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
Map<String, String> params = new HashMap<>();
params.put("grant_type", "authorization_code");
params.put("client_id", config.getClientId());
params.put("client_secret", config.getClientSecret());
params.put("code", authCallback.getCode());
params.put("redirect_uri", config.getRedirectUri());
String response = new HttpUtils(config.getHttpConfig()).post(AuthDefaultSource.AFDIAN.accessToken(), params, false).getBody();
JSONObject accessTokenObject = JSONObject.parseObject(response);
String userId = accessTokenObject.getJSONObject("data").getString("user_id");
return AuthToken.builder().userId(userId).build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
return AuthUser.builder()
.uuid(authToken.getUserId())
.gender(AuthUserGender.UNKNOWN)
.token(authToken)
.source(source.toString())
.build();
}
/**
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
*/
@Override
public String authorize(String state) {
return UrlBuilder.fromBaseUrl(source.authorize())
.queryParam("response_type", "code")
.queryParam("scope", "basic")
.queryParam("client_id", config.getClientId())
.queryParam("redirect_uri", config.getRedirectUri())
.queryParam("state", getRealState(state))
.build();
}
}
@@ -18,9 +18,13 @@ import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.utils.AuthChecker;
import me.zhyd.oauth.utils.GlobalAuthUtils;
import me.zhyd.oauth.utils.StringUtils;
import me.zhyd.oauth.utils.UrlBuilder;
import java.net.InetSocketAddress;
/**
* 支付宝登录
*
@@ -29,18 +33,117 @@ import me.zhyd.oauth.utils.UrlBuilder;
*/
public class AuthAlipayRequest extends AuthDefaultRequest {
private AlipayClient alipayClient;
/**
* 支付宝公钥:当选择支付宝登录时,该值可用
* 对应“RSA2(SHA256)密钥”中的“支付宝公钥”
*/
private final String alipayPublicKey;
private final AlipayClient alipayClient;
private static final String GATEWAY = "https://openapi.alipay.com/gateway.do";
/**
* @see AuthAlipayRequest#AuthAlipayRequest(me.zhyd.oauth.config.AuthConfig, java.lang.String)
* @deprecated 请使用带有"alipayPublicKey"参数的构造方法
*/
@Deprecated
public AuthAlipayRequest(AuthConfig config) {
super(config, AuthDefaultSource.ALIPAY);
this.alipayClient = new DefaultAlipayClient(AuthDefaultSource.ALIPAY.accessToken(), config.getClientId(), config.getClientSecret(), "json", "UTF-8", config
.getAlipayPublicKey(), "RSA2");
this(config, (String) null);
}
/**
* @see AuthAlipayRequest#AuthAlipayRequest(me.zhyd.oauth.config.AuthConfig, java.lang.String, me.zhyd.oauth.cache.AuthStateCache)
* @deprecated 请使用带有"alipayPublicKey"参数的构造方法
*/
@Deprecated
public AuthAlipayRequest(AuthConfig config, AuthStateCache authStateCache) {
this(config, null, authStateCache);
}
/**
* @see AuthAlipayRequest#AuthAlipayRequest(me.zhyd.oauth.config.AuthConfig, java.lang.String, me.zhyd.oauth.cache.AuthStateCache, java.lang.String, java.lang.Integer)
* @deprecated 请使用带有"alipayPublicKey"参数的构造方法
*/
@Deprecated
public AuthAlipayRequest(AuthConfig config, AuthStateCache authStateCache, String proxyHost, Integer proxyPort) {
this(config, null, authStateCache, proxyHost, proxyPort);
}
/**
* 构造方法,需要设置"alipayPublicKey"
*
* @param config 公共的OAuth配置
* @param alipayPublicKey 支付宝公钥
* @see AuthAlipayRequest#AuthAlipayRequest(me.zhyd.oauth.config.AuthConfig)
*/
public AuthAlipayRequest(AuthConfig config, String alipayPublicKey) {
super(config, AuthDefaultSource.ALIPAY);
this.alipayPublicKey = determineAlipayPublicKey(alipayPublicKey, config);
check(config);
this.alipayClient = new DefaultAlipayClient(GATEWAY, config.getClientId(), config.getClientSecret(), "json", "UTF-8", this.alipayPublicKey, "RSA2");
}
/**
* 构造方法,需要设置"alipayPublicKey"
*
* @param config 公共的OAuth配置
* @param alipayPublicKey 支付宝公钥
* @see AuthAlipayRequest#AuthAlipayRequest(me.zhyd.oauth.config.AuthConfig, me.zhyd.oauth.cache.AuthStateCache)
*/
public AuthAlipayRequest(AuthConfig config, String alipayPublicKey, AuthStateCache authStateCache) {
super(config, AuthDefaultSource.ALIPAY, authStateCache);
this.alipayClient = new DefaultAlipayClient(AuthDefaultSource.ALIPAY.accessToken(), config.getClientId(), config.getClientSecret(), "json", "UTF-8", config
.getAlipayPublicKey(), "RSA2");
this.alipayPublicKey = determineAlipayPublicKey(alipayPublicKey, config);
check(config);
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(GATEWAY, config.getClientId(), config.getClientSecret(),
"json", "UTF-8", this.alipayPublicKey, "RSA2", address.getHostName(), address.getPort());
} else {
this.alipayClient = new DefaultAlipayClient(GATEWAY, config.getClientId(), config.getClientSecret(),
"json", "UTF-8", this.alipayPublicKey, "RSA2");
}
}
/**
* 构造方法,需要设置"alipayPublicKey"
*
* @param config 公共的OAuth配置
* @param alipayPublicKey 支付宝公钥
* @see AuthAlipayRequest#AuthAlipayRequest(me.zhyd.oauth.config.AuthConfig, me.zhyd.oauth.cache.AuthStateCache, java.lang.String, java.lang.Integer)
*/
public AuthAlipayRequest(AuthConfig config, String alipayPublicKey, AuthStateCache authStateCache, String proxyHost, Integer proxyPort) {
super(config, AuthDefaultSource.ALIPAY, authStateCache);
this.alipayPublicKey = determineAlipayPublicKey(alipayPublicKey, config);
check(config);
this.alipayClient = new DefaultAlipayClient(GATEWAY, config.getClientId(), config.getClientSecret(),
"json", "UTF-8", this.alipayPublicKey, "RSA2", proxyHost, proxyPort);
}
private String determineAlipayPublicKey(String alipayPublicKey, AuthConfig config) {
return alipayPublicKey != null ? alipayPublicKey : config.getAlipayPublicKey();
}
protected void check(AuthConfig config) {
AuthChecker.checkConfig(config, AuthDefaultSource.ALIPAY);
if (!StringUtils.isNotEmpty(alipayPublicKey)) {
throw new AuthException(AuthResponseStatus.PARAMETER_INCOMPLETE, AuthDefaultSource.ALIPAY);
}
// 支付宝在创建回调地址时,不允许使用localhost或者127.0.0.1
if (GlobalAuthUtils.isLocalHost(config.getRedirectUri())) {
// The redirect uri of alipay is forbidden to use localhost or 127.0.0.1
throw new AuthException(AuthResponseStatus.ILLEGAL_REDIRECT_URI, AuthDefaultSource.ALIPAY);
}
}
@Override
protected void checkCode(AuthCallback authCallback) {
if (StringUtils.isEmpty(authCallback.getAuth_code())) {
throw new AuthException(AuthResponseStatus.ILLEGAL_CODE, source);
}
}
@Override
@@ -48,7 +151,7 @@ public class AuthAlipayRequest extends AuthDefaultRequest {
AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
request.setGrantType("authorization_code");
request.setCode(authCallback.getAuth_code());
AlipaySystemOauthTokenResponse response = null;
AlipaySystemOauthTokenResponse response;
try {
response = this.alipayClient.execute(request);
} catch (Exception e) {
@@ -8,7 +8,6 @@ import me.zhyd.oauth.enums.AuthUserGender;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.utils.UrlBuilder;
/**
* 阿里云登录
@@ -31,12 +30,12 @@ public class AuthAliyunRequest extends AuthDefaultRequest {
String response = doPostAuthorizationCode(authCallback.getCode());
JSONObject accessTokenObject = JSONObject.parseObject(response);
return AuthToken.builder()
.accessToken(accessTokenObject.getString("access_token"))
.expireIn(accessTokenObject.getIntValue("expires_in"))
.tokenType(accessTokenObject.getString("token_type"))
.idToken(accessTokenObject.getString("id_token"))
.refreshToken(accessTokenObject.getString("refresh_token"))
.build();
.accessToken(accessTokenObject.getString("access_token"))
.expireIn(accessTokenObject.getIntValue("expires_in"))
.tokenType(accessTokenObject.getString("token_type"))
.idToken(accessTokenObject.getString("id_token"))
.refreshToken(accessTokenObject.getString("refresh_token"))
.build();
}
@Override
@@ -0,0 +1,182 @@
package me.zhyd.oauth.request;
import com.alibaba.fastjson.JSONObject;
import com.xkcoding.http.constants.Constants;
import com.xkcoding.http.support.HttpHeader;
import com.xkcoding.http.util.UrlUtil;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.config.AuthDefaultSource;
import me.zhyd.oauth.enums.AuthResponseStatus;
import me.zhyd.oauth.enums.AuthUserGender;
import me.zhyd.oauth.enums.scope.AuthAmazonScope;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.utils.AuthScopeUtils;
import me.zhyd.oauth.utils.HttpUtils;
import me.zhyd.oauth.utils.PkceUtil;
import me.zhyd.oauth.utils.UrlBuilder;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* Amazon登录
* Login with Amazon for Websites Overview https://developer.amazon.com/zh/docs/login-with-amazon/register-web.html
* Login with Amazon SDK for JavaScript Reference Guidehttps://developer.amazon.com/zh/docs/login-with-amazon/javascript-sdk-reference.html
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @since 1.16.0
*/
public class AuthAmazonRequest extends AuthDefaultRequest {
public AuthAmazonRequest(AuthConfig config) {
super(config, AuthDefaultSource.AMAZON);
}
public AuthAmazonRequest(AuthConfig config, AuthStateCache authStateCache) {
super(config, AuthDefaultSource.AMAZON, authStateCache);
}
/**
* https://developer.amazon.com/zh/docs/login-with-amazon/authorization-code-grant.html#authorization-request
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return String
*/
@Override
public String authorize(String state) {
UrlBuilder builder = UrlBuilder.fromBaseUrl(source.authorize())
.queryParam("client_id", config.getClientId())
.queryParam("scope", this.getScopes(" ", true, AuthScopeUtils.getDefaultScopes(AuthAmazonScope.values())))
.queryParam("redirect_uri", config.getRedirectUri())
.queryParam("response_type", "code")
.queryParam("state", getRealState(state));
if (config.isPkce()) {
String cacheKey = this.source.getName().concat(":code_verifier:").concat(config.getClientId());
String codeVerifier = PkceUtil.generateCodeVerifier();
String codeChallengeMethod = "S256";
String codeChallenge = PkceUtil.generateCodeChallenge(codeChallengeMethod, codeVerifier);
builder.queryParam("code_challenge", codeChallenge)
.queryParam("code_challenge_method", codeChallengeMethod);
// 缓存 codeVerifier 十分钟
this.authStateCache.cache(cacheKey, codeVerifier, TimeUnit.MINUTES.toMillis(10));
}
return builder.build();
}
/**
* https://developer.amazon.com/zh/docs/login-with-amazon/authorization-code-grant.html#access-token-request
*
* @return access token
*/
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
Map<String, String> form = new HashMap<>(9);
form.put("grant_type", "authorization_code");
form.put("code", authCallback.getCode());
form.put("redirect_uri", config.getRedirectUri());
form.put("client_id", config.getClientId());
form.put("client_secret", config.getClientSecret());
if (config.isPkce()) {
String cacheKey = this.source.getName().concat(":code_verifier:").concat(config.getClientId());
String codeVerifier = this.authStateCache.get(cacheKey);
form.put("code_verifier", codeVerifier);
}
return getToken(form, this.source.accessToken());
}
@Override
public AuthResponse refresh(AuthToken authToken) {
Map<String, String> form = new HashMap<>(7);
form.put("grant_type", "refresh_token");
form.put("refresh_token", authToken.getRefreshToken());
form.put("client_id", config.getClientId());
form.put("client_secret", config.getClientSecret());
return AuthResponse.builder()
.code(AuthResponseStatus.SUCCESS.getCode())
.data(getToken(form, this.source.refresh()))
.build();
}
private AuthToken getToken(Map<String, String> param, String url) {
HttpHeader httpHeader = new HttpHeader();
httpHeader.add("Host", "api.amazon.com");
httpHeader.add(Constants.CONTENT_TYPE, "application/x-www-form-urlencoded;charset=UTF-8");
String response = new HttpUtils(config.getHttpConfig()).post(url, param, httpHeader, false).getBody();
JSONObject jsonObject = JSONObject.parseObject(response);
this.checkResponse(jsonObject);
return AuthToken.builder()
.accessToken(jsonObject.getString("access_token"))
.tokenType(jsonObject.getString("token_type"))
.expireIn(jsonObject.getIntValue("expires_in"))
.refreshToken(jsonObject.getString("refresh_token"))
.build();
}
/**
* 校验响应内容是否正确
*
* @param jsonObject 响应内容
*/
private void checkResponse(JSONObject jsonObject) {
if (jsonObject.containsKey("error")) {
throw new AuthException(jsonObject.getString("error_description").concat(" ") + jsonObject.getString("error_description"));
}
}
/**
* https://developer.amazon.com/zh/docs/login-with-amazon/obtain-customer-profile.html#call-profile-endpoint
*
* @param authToken token信息
* @return AuthUser
*/
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String accessToken = authToken.getAccessToken();
this.checkToken(accessToken);
HttpHeader httpHeader = new HttpHeader();
httpHeader.add("Host", "api.amazon.com");
httpHeader.add("Authorization", "bearer " + accessToken);
String userInfo = new HttpUtils(config.getHttpConfig()).get(this.source.userInfo(), new HashMap<>(0), httpHeader, false).getBody();
JSONObject jsonObject = JSONObject.parseObject(userInfo);
this.checkResponse(jsonObject);
return AuthUser.builder()
.rawUserInfo(jsonObject)
.uuid(jsonObject.getString("user_id"))
.username(jsonObject.getString("name"))
.nickname(jsonObject.getString("name"))
.email(jsonObject.getString("email"))
.gender(AuthUserGender.UNKNOWN)
.source(source.toString())
.token(authToken)
.build();
}
private void checkToken(String accessToken) {
String tokenInfo = new HttpUtils(config.getHttpConfig()).get("https://api.amazon.com/auth/o2/tokeninfo?access_token=" + UrlUtil.urlEncode(accessToken)).getBody();
JSONObject jsonObject = JSONObject.parseObject(tokenInfo);
if (!config.getClientId().equals(jsonObject.getString("aud"))) {
throw new AuthException(AuthResponseStatus.ILLEGAL_TOKEN);
}
}
@Override
protected String userInfoUrl(AuthToken authToken) {
return UrlBuilder.fromBaseUrl(source.userInfo())
.queryParam("user_id", authToken.getUserId())
.queryParam("screen_name", authToken.getScreenName())
.queryParam("include_entities", true)
.build();
}
}
@@ -88,7 +88,7 @@ public class AuthBaiduRequest extends AuthDefaultRequest {
.queryParam("client_id", this.config.getClientId())
.queryParam("client_secret", this.config.getClientSecret())
.build();
String response = new HttpUtils(config.getHttpConfig()).get(refreshUrl);
String response = new HttpUtils(config.getHttpConfig()).get(refreshUrl).getBody();
return AuthResponse.builder()
.code(AuthResponseStatus.SUCCESS.getCode())
.data(this.getAuthToken(response))
@@ -14,7 +14,7 @@ import me.zhyd.oauth.utils.AuthScopeUtils;
import me.zhyd.oauth.utils.UrlBuilder;
/**
* Cooding登录
* Coding登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @since 1.0.0
@@ -85,7 +85,7 @@ public class AuthCodingRequest extends AuthDefaultRequest {
*/
@Override
public String authorize(String state) {
return UrlBuilder.fromBaseUrl(String.format(source.authorize(), config.getCodingGroupName()))
return UrlBuilder.fromBaseUrl(String.format(source.authorize(), config.getDomainPrefix()))
.queryParam("response_type", "code")
.queryParam("client_id", config.getClientId())
.queryParam("redirect_uri", config.getRedirectUri())
@@ -102,7 +102,7 @@ public class AuthCodingRequest extends AuthDefaultRequest {
*/
@Override
public String accessTokenUrl(String code) {
return UrlBuilder.fromBaseUrl(String.format(source.accessToken(), config.getCodingGroupName()))
return UrlBuilder.fromBaseUrl(String.format(source.accessToken(), config.getDomainPrefix()))
.queryParam("code", code)
.queryParam("client_id", config.getClientId())
.queryParam("client_secret", config.getClientSecret())
@@ -119,7 +119,7 @@ public class AuthCodingRequest extends AuthDefaultRequest {
*/
@Override
public String userInfoUrl(AuthToken authToken) {
return UrlBuilder.fromBaseUrl(String.format(source.userInfo(), config.getCodingGroupName()))
return UrlBuilder.fromBaseUrl(String.format(source.userInfo(), config.getDomainPrefix()))
.queryParam("access_token", authToken.getAccessToken())
.build();
}
@@ -72,7 +72,7 @@ public abstract class AuthDefaultRequest implements AuthRequest {
@Override
public AuthResponse login(AuthCallback authCallback) {
try {
AuthChecker.checkCode(source, authCallback);
checkCode(authCallback);
if (!config.isIgnoreCheckState()) {
AuthChecker.checkState(authCallback.getState(), source, authStateCache);
}
@@ -86,13 +86,17 @@ public abstract class AuthDefaultRequest implements AuthRequest {
}
}
protected void checkCode(AuthCallback authCallback) {
AuthChecker.checkCode(source, authCallback);
}
/**
* 处理{@link AuthDefaultRequest#login(AuthCallback)} 发生异常的情况,统一响应参数
*
* @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) {
@@ -211,7 +215,7 @@ public abstract class AuthDefaultRequest implements AuthRequest {
* @return Response
*/
protected String doPostAuthorizationCode(String code) {
return new HttpUtils(config.getHttpConfig()).post(accessTokenUrl(code));
return new HttpUtils(config.getHttpConfig()).post(accessTokenUrl(code)).getBody();
}
/**
@@ -221,7 +225,7 @@ public abstract class AuthDefaultRequest implements AuthRequest {
* @return Response
*/
protected String doGetAuthorizationCode(String code) {
return new HttpUtils(config.getHttpConfig()).get(accessTokenUrl(code));
return new HttpUtils(config.getHttpConfig()).get(accessTokenUrl(code)).getBody();
}
/**
@@ -232,7 +236,7 @@ public abstract class AuthDefaultRequest implements AuthRequest {
*/
@Deprecated
protected String doPostUserInfo(AuthToken authToken) {
return new HttpUtils(config.getHttpConfig()).post(userInfoUrl(authToken));
return new HttpUtils(config.getHttpConfig()).post(userInfoUrl(authToken)).getBody();
}
/**
@@ -242,7 +246,7 @@ public abstract class AuthDefaultRequest implements AuthRequest {
* @return Response
*/
protected String doGetUserInfo(AuthToken authToken) {
return new HttpUtils(config.getHttpConfig()).get(userInfoUrl(authToken));
return new HttpUtils(config.getHttpConfig()).get(userInfoUrl(authToken)).getBody();
}
/**
@@ -253,7 +257,7 @@ public abstract class AuthDefaultRequest implements AuthRequest {
*/
@Deprecated
protected String doPostRevoke(AuthToken authToken) {
return new HttpUtils(config.getHttpConfig()).post(revokeUrl(authToken));
return new HttpUtils(config.getHttpConfig()).post(revokeUrl(authToken)).getBody();
}
/**
@@ -263,7 +267,7 @@ public abstract class AuthDefaultRequest implements AuthRequest {
* @return Response
*/
protected String doGetRevoke(AuthToken authToken) {
return new HttpUtils(config.getHttpConfig()).get(revokeUrl(authToken));
return new HttpUtils(config.getHttpConfig()).get(revokeUrl(authToken)).getBody();
}
/**
@@ -0,0 +1,22 @@
package me.zhyd.oauth.request;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.config.AuthDefaultSource;
/**
* 钉钉账号登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @since 1.0.0
*/
public class AuthDingTalkAccountRequest extends AbstractAuthDingtalkRequest {
public AuthDingTalkAccountRequest(AuthConfig config) {
super(config, AuthDefaultSource.DINGTALK_ACCOUNT);
}
public AuthDingTalkAccountRequest(AuthConfig config, AuthStateCache authStateCache) {
super(config, AuthDefaultSource.DINGTALK_ACCOUNT, authStateCache);
}
}
@@ -1,26 +1,16 @@
package me.zhyd.oauth.request;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import me.zhyd.oauth.utils.HttpUtils;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.config.AuthDefaultSource;
import me.zhyd.oauth.enums.AuthUserGender;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.utils.GlobalAuthUtils;
import me.zhyd.oauth.utils.UrlBuilder;
/**
* 钉钉登录
* 钉钉二维码登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @since 1.0.0
*/
public class AuthDingTalkRequest extends AuthDefaultRequest {
public class AuthDingTalkRequest extends AbstractAuthDingtalkRequest {
public AuthDingTalkRequest(AuthConfig config) {
super(config, AuthDefaultSource.DINGTALK);
@@ -29,72 +19,4 @@ public class AuthDingTalkRequest extends AuthDefaultRequest {
public AuthDingTalkRequest(AuthConfig config, AuthStateCache authStateCache) {
super(config, AuthDefaultSource.DINGTALK, authStateCache);
}
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
return AuthToken.builder().accessCode(authCallback.getCode()).build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String code = authToken.getAccessCode();
JSONObject param = new JSONObject();
param.put("tmp_auth_code", code);
String response = new HttpUtils(config.getHttpConfig()).post(userInfoUrl(authToken), param.toJSONString());
JSONObject object = JSON.parseObject(response);
if (object.getIntValue("errcode") != 0) {
throw new AuthException(object.getString("errmsg"));
}
object = object.getJSONObject("user_info");
AuthToken token = AuthToken.builder()
.openId(object.getString("openid"))
.unionId(object.getString("unionid"))
.build();
return AuthUser.builder()
.rawUserInfo(object)
.uuid(object.getString("unionid"))
.nickname(object.getString("nick"))
.username(object.getString("nick"))
.gender(AuthUserGender.UNKNOWN)
.source(source.toString())
.token(token)
.build();
}
/**
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public String authorize(String state) {
return UrlBuilder.fromBaseUrl(source.authorize())
.queryParam("response_type", "code")
.queryParam("appid", config.getClientId())
.queryParam("scope", "snsapi_login")
.queryParam("redirect_uri", config.getRedirectUri())
.queryParam("state", getRealState(state))
.build();
}
/**
* 返回获取userInfo的url
*
* @param authToken 用户授权后的token
* @return 返回获取userInfo的url
*/
@Override
protected String userInfoUrl(AuthToken authToken) {
// 根据timestamp, appSecret计算签名值
String timestamp = System.currentTimeMillis() + "";
String urlEncodeSignature = GlobalAuthUtils.generateDingTalkSignature(config.getClientSecret(), timestamp);
return UrlBuilder.fromBaseUrl(source.userInfo())
.queryParam("signature", urlEncodeSignature)
.queryParam("timestamp", timestamp)
.queryParam("accessKey", config.getClientId())
.build();
}
}
@@ -1,17 +1,19 @@
package me.zhyd.oauth.request;
import com.alibaba.fastjson.JSONObject;
import me.zhyd.oauth.utils.HttpUtils;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.config.AuthDefaultSource;
import me.zhyd.oauth.enums.AuthResponseStatus;
import me.zhyd.oauth.enums.AuthUserGender;
import me.zhyd.oauth.enums.scope.AuthDouyinScope;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.utils.AuthScopeUtils;
import me.zhyd.oauth.utils.HttpUtils;
import me.zhyd.oauth.utils.UrlBuilder;
@@ -85,7 +87,7 @@ public class AuthDouyinRequest extends AuthDefaultRequest {
* @return token对象
*/
private AuthToken getToken(String accessTokenUrl) {
String response = new HttpUtils(config.getHttpConfig()).post(accessTokenUrl);
String response = new HttpUtils(config.getHttpConfig()).post(accessTokenUrl).getBody();
JSONObject object = JSONObject.parseObject(response);
this.checkResponse(object);
JSONObject dataObj = object.getJSONObject("data");
@@ -111,7 +113,7 @@ public class AuthDouyinRequest extends AuthDefaultRequest {
.queryParam("response_type", "code")
.queryParam("client_key", config.getClientId())
.queryParam("redirect_uri", config.getRedirectUri())
.queryParam("scope", "user_info")
.queryParam("scope", this.getScopes(",", true, AuthScopeUtils.getDefaultScopes(AuthDouyinScope.values())))
.queryParam("state", getRealState(state))
.build();
}
@@ -45,14 +45,14 @@ public class AuthElemeRequest extends AuthDefaultRequest {
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
Map<String, String> form = new HashMap<>(4);
Map<String, String> form = new HashMap<>(7);
form.put("client_id", config.getClientId());
form.put("redirect_uri", config.getRedirectUri());
form.put("code", authCallback.getCode());
form.put("grant_type", "authorization_code");
HttpHeader httpHeader = this.buildHeader(CONTENT_TYPE_FORM, this.getRequestId(), true);
String response = new HttpUtils(config.getHttpConfig()).post(source.accessToken(), form, httpHeader, false);
String response = new HttpUtils(config.getHttpConfig()).post(source.accessToken(), form, httpHeader, false).getBody();
JSONObject object = JSONObject.parseObject(response);
this.checkResponse(object);
@@ -67,13 +67,13 @@ public class AuthElemeRequest extends AuthDefaultRequest {
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
Map<String, Object> parameters = new HashMap<>();
Map<String, Object> parameters = new HashMap<>(4);
// 获取商户账号信息的API接口名称
String action = "eleme.user.getUser";
// 时间戳,单位秒。API服务端允许客户端请求最大时间误差为正负5分钟。
final long timestamp = System.currentTimeMillis();
// 公共参数
Map<String, Object> metasHashMap = new HashMap<>();
Map<String, Object> metasHashMap = new HashMap<>(4);
metasHashMap.put("app_key", config.getClientId());
metasHashMap.put("timestamp", timestamp);
String signature = GlobalAuthUtils.generateElemeSignature(config.getClientId(), config.getClientSecret(), timestamp, action, authToken
@@ -91,7 +91,7 @@ public class AuthElemeRequest extends AuthDefaultRequest {
paramsMap.put("signature", signature);
HttpHeader httpHeader = this.buildHeader(CONTENT_TYPE_JSON, requestId, false);
String response = new HttpUtils(config.getHttpConfig()).post(source.userInfo(), JSONObject.toJSONString(paramsMap), httpHeader);
String response = new HttpUtils(config.getHttpConfig()).post(source.userInfo(), JSONObject.toJSONString(paramsMap), httpHeader).getBody();
JSONObject object = JSONObject.parseObject(response);
@@ -118,12 +118,12 @@ public class AuthElemeRequest extends AuthDefaultRequest {
@Override
public AuthResponse refresh(AuthToken oldToken) {
Map<String, String> form = new HashMap<>(2);
Map<String, String> form = new HashMap<>(4);
form.put("refresh_token", oldToken.getRefreshToken());
form.put("grant_type", "refresh_token");
HttpHeader httpHeader = this.buildHeader(CONTENT_TYPE_FORM, this.getRequestId(), true);
String response = new HttpUtils(config.getHttpConfig()).post(source.refresh(), form, httpHeader, false);
String response = new HttpUtils(config.getHttpConfig()).post(source.refresh(), form, httpHeader, false).getBody();
JSONObject object = JSONObject.parseObject(response);
@@ -3,9 +3,11 @@ package me.zhyd.oauth.request;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xkcoding.http.support.HttpHeader;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.config.AuthDefaultSource;
import me.zhyd.oauth.enums.AuthResponseStatus;
import me.zhyd.oauth.enums.AuthUserGender;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
@@ -13,40 +15,63 @@ import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.utils.GlobalAuthUtils;
import me.zhyd.oauth.utils.HttpUtils;
import me.zhyd.oauth.utils.StringUtils;
import me.zhyd.oauth.utils.UrlBuilder;
/**
* 注意:该平台暂时存在问题,请不要使用。待修复完成后会重新发版by yadong.zhang
* 飞书平台,企业自建应用授权登录,原逻辑由 beacon 集成于 1.14.0 版,但最新的飞书 api 已修改,并且飞书平台一直为 {@code Deprecated} 状态
* <p>
* 所以,最终修改该平台的实际发布版本为 1.15.9
*
* @author beacon
* @since 1.14.0
* @author yadong.zhang (yadong.zhang0415(a)gmail.com) 重构业务逻辑 20210101
* @since 1.15.9
*/
@Deprecated
public class AuthFeishuRequest extends AuthDefaultRequest {
public AuthFeishuRequest(AuthConfig config) {
super(config, AuthDefaultSource.FEISHU);
throw new AuthException(AuthResponseStatus.FAILURE);
}
public AuthFeishuRequest(AuthConfig config, AuthStateCache authStateCache) {
super(config, AuthDefaultSource.FEISHU, authStateCache);
}
/**
* 获取 app_access_token(企业自建应用)
* <p>
* Token 有效期为 2 小时,在此期间调用该接口 token 不会改变。当 token 有效期小于 30 分的时候,再次请求获取 token 的时候,
* 会生成一个新的 token,与此同时老的 token 依然有效。
*
* @return appAccessToken
*/
private String getAppAccessToken() {
String cacheKey = this.source.getName().concat(":app_access_token:").concat(config.getClientId());
String cacheAppAccessToken = this.authStateCache.get(cacheKey);
if (StringUtils.isNotEmpty(cacheAppAccessToken)) {
return cacheAppAccessToken;
}
String url = "https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal/";
JSONObject requestObject = new JSONObject();
requestObject.put("app_id", config.getClientId());
requestObject.put("app_secret", config.getClientSecret());
String response = new HttpUtils(config.getHttpConfig()).post(url, requestObject.toJSONString(), new HttpHeader()
.add("Content-Type", "application/json")).getBody();
JSONObject jsonObject = JSON.parseObject(response);
this.checkResponse(jsonObject);
String appAccessToken = jsonObject.getString("app_access_token");
// 缓存 app access token
this.authStateCache.cache(cacheKey, appAccessToken, jsonObject.getLongValue("expire") * 1000);
return appAccessToken;
}
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
JSONObject requestObject = new JSONObject();
requestObject.put("app_id", config.getClientId());
requestObject.put("app_secret", config.getClientSecret());
requestObject.put("app_access_token", this.getAppAccessToken());
requestObject.put("grant_type", "authorization_code");
requestObject.put("code", authCallback.getCode());
String response = new HttpUtils(config.getHttpConfig()).post(source.accessToken(), requestObject.toJSONString(), new HttpHeader()
.add("Content-Type", "application/json"));
JSONObject jsonObject = JSON.parseObject(response);
this.checkResponse(jsonObject);
return AuthToken.builder()
.accessToken(jsonObject.getString("access_token"))
.refreshToken(jsonObject.getString("refresh_token"))
.expireIn(jsonObject.getIntValue("expires_in"))
.tokenType(jsonObject.getString("token_type"))
.openId(jsonObject.getString("open_id"))
.build();
return getToken(requestObject, this.source.accessToken());
}
@@ -55,41 +80,51 @@ public class AuthFeishuRequest extends AuthDefaultRequest {
String accessToken = authToken.getAccessToken();
String response = new HttpUtils(config.getHttpConfig()).get(source.userInfo(), null, new HttpHeader()
.add("Content-Type", "application/json")
.add("Authorization", "Bearer " + accessToken), false);
.add("Authorization", "Bearer " + accessToken), false).getBody();
JSONObject object = JSON.parseObject(response);
this.checkResponse(object);
JSONObject data = object.getJSONObject("data");
return AuthUser.builder()
.rawUserInfo(object)
.avatar(object.getString("AvatarUrl"))
.username(object.getString("Mobile"))
.email(object.getString("Email"))
.nickname("Name")
.uuid(data.getString("union_id"))
.username(data.getString("name"))
.nickname(data.getString("name"))
.avatar(data.getString("avatar_url"))
.email(data.getString("email"))
.gender(AuthUserGender.UNKNOWN)
.token(authToken)
.source(source.toString())
.build();
}
@Override
public AuthResponse refresh(AuthToken authToken) {
JSONObject requestObject = new JSONObject();
requestObject.put("app_id", config.getClientId());
requestObject.put("app_secret", config.getClientSecret());
requestObject.put("app_access_token", this.getAppAccessToken());
requestObject.put("grant_type", "refresh_token");
requestObject.put("refresh_token", authToken.getRefreshToken());
String response = new HttpUtils(config.getHttpConfig()).post(source.refresh(), requestObject.toJSONString(), new HttpHeader()
.add("Content-Type", "application/json"));
JSONObject jsonObject = JSON.parseObject(response);
this.checkResponse(jsonObject);
return AuthResponse.builder()
.code(AuthResponseStatus.SUCCESS.getCode())
.data(AuthToken.builder()
.accessToken(jsonObject.getString("access_token"))
.refreshToken(jsonObject.getString("refresh_token"))
.expireIn(jsonObject.getIntValue("expires_in"))
.tokenType(jsonObject.getString("token_type"))
.openId(jsonObject.getString("open_id"))
.build())
.data(getToken(requestObject, this.source.refresh()))
.build();
}
private AuthToken getToken(JSONObject param, String url) {
String response = new HttpUtils(config.getHttpConfig()).post(url, param.toJSONString(), new HttpHeader()
.add("Content-Type", "application/json")).getBody();
JSONObject jsonObject = JSON.parseObject(response);
this.checkResponse(jsonObject);
JSONObject data = jsonObject.getJSONObject("data");
return AuthToken.builder()
.accessToken(data.getString("access_token"))
.refreshToken(data.getString("refresh_token"))
.expireIn(data.getIntValue("expires_in"))
.tokenType(data.getString("token_type"))
.openId(data.getString("open_id"))
.build();
}
@Override
public String authorize(String state) {
return UrlBuilder.fromBaseUrl(source.authorize())
@@ -52,7 +52,7 @@ public class AuthGithubRequest extends AuthDefaultRequest {
protected AuthUser getUserInfo(AuthToken authToken) {
HttpHeader header = new HttpHeader();
header.add("Authorization", "token " + authToken.getAccessToken());
String response = new HttpUtils(config.getHttpConfig()).get(UrlBuilder.fromBaseUrl(source.userInfo()).build(), null, header, false);
String response = new HttpUtils(config.getHttpConfig()).get(UrlBuilder.fromBaseUrl(source.userInfo()).build(), null, header, false).getBody();
JSONObject object = JSONObject.parseObject(response);
this.checkResponse(object.containsKey("error"), object.getString("error_description"));
@@ -50,7 +50,7 @@ public class AuthGoogleRequest extends AuthDefaultRequest {
protected AuthUser getUserInfo(AuthToken authToken) {
HttpHeader httpHeader = new HttpHeader();
httpHeader.add("Authorization", "Bearer " + authToken.getAccessToken());
String userInfo = new HttpUtils(config.getHttpConfig()).post(userInfoUrl(authToken), null, httpHeader);
String userInfo = new HttpUtils(config.getHttpConfig()).post(userInfoUrl(authToken), null, httpHeader).getBody();
JSONObject object = JSONObject.parseObject(userInfo);
this.checkResponse(object);
return AuthUser.builder()
@@ -47,14 +47,14 @@ public class AuthHuaweiRequest extends AuthDefaultRequest {
*/
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
Map<String, String> form = new HashMap<>(5);
Map<String, String> form = new HashMap<>(8);
form.put("grant_type", "authorization_code");
form.put("code", authCallback.getAuthorization_code());
form.put("client_id", config.getClientId());
form.put("client_secret", config.getClientSecret());
form.put("redirect_uri", config.getRedirectUri());
String response = new HttpUtils(config.getHttpConfig()).post(source.accessToken(), form, false);
String response = new HttpUtils(config.getHttpConfig()).post(source.accessToken(), form, false).getBody();
return getAuthToken(response);
}
@@ -67,13 +67,13 @@ public class AuthHuaweiRequest extends AuthDefaultRequest {
*/
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
Map<String, String> form = new HashMap<>(4);
Map<String, String> form = new HashMap<>(7);
form.put("nsp_ts", System.currentTimeMillis() + "");
form.put("access_token", authToken.getAccessToken());
form.put("nsp_fmt", "JS");
form.put("nsp_svc", "OpenUP.User.getInfo");
String response = new HttpUtils(config.getHttpConfig()).post(source.userInfo(), form, false);
String response = new HttpUtils(config.getHttpConfig()).post(source.userInfo(), form, false).getBody();
JSONObject object = JSONObject.parseObject(response);
this.checkResponse(object);
@@ -100,13 +100,13 @@ public class AuthHuaweiRequest extends AuthDefaultRequest {
*/
@Override
public AuthResponse refresh(AuthToken authToken) {
Map<String, String> form = new HashMap<>(4);
Map<String, String> form = new HashMap<>(7);
form.put("client_id", config.getClientId());
form.put("client_secret", config.getClientSecret());
form.put("refresh_token", authToken.getRefreshToken());
form.put("grant_type", "refresh_token");
String response = new HttpUtils(config.getHttpConfig()).post(source.refresh(), form, false);
String response = new HttpUtils(config.getHttpConfig()).post(source.refresh(), form, false).getBody();
return AuthResponse.builder().code(SUCCESS.getCode()).data(getAuthToken(response)).build();
}
@@ -41,12 +41,12 @@ public class AuthJdRequest extends AuthDefaultRequest {
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
Map<String, String> params = new HashMap<>(5);
Map<String, String> params = new HashMap<>(7);
params.put("app_key", config.getClientId());
params.put("app_secret", config.getClientSecret());
params.put("grant_type", "authorization_code");
params.put("code", authCallback.getCode());
String response = new HttpUtils(config.getHttpConfig()).post(source.accessToken(), params, false);
String response = new HttpUtils(config.getHttpConfig()).post(source.accessToken(), params, false).getBody();
JSONObject object = JSONObject.parseObject(response);
this.checkResponse(object);
@@ -70,7 +70,7 @@ public class AuthJdRequest extends AuthDefaultRequest {
.queryParam("timestamp", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
.queryParam("v", "2.0");
urlBuilder.queryParam("sign", GlobalAuthUtils.generateJdSignature(config.getClientSecret(), urlBuilder.getReadOnlyParams()));
String response = new HttpUtils(config.getHttpConfig()).post(urlBuilder.build(true));
String response = new HttpUtils(config.getHttpConfig()).post(urlBuilder.build(true)).getBody();
JSONObject object = JSONObject.parseObject(response);
this.checkResponse(object);
@@ -104,12 +104,12 @@ public class AuthJdRequest extends AuthDefaultRequest {
@Override
public AuthResponse refresh(AuthToken oldToken) {
Map<String, String> params = new HashMap<>(5);
Map<String, String> params = new HashMap<>(7);
params.put("app_key", config.getClientId());
params.put("app_secret", config.getClientSecret());
params.put("grant_type", "refresh_token");
params.put("refresh_token", oldToken.getRefreshToken());
String response = new HttpUtils(config.getHttpConfig()).post(source.refresh(), params, false);
String response = new HttpUtils(config.getHttpConfig()).post(source.refresh(), params, false).getBody();
JSONObject object = JSONObject.parseObject(response);
this.checkResponse(object);
@@ -76,7 +76,7 @@ public class AuthKujialeRequest extends AuthDefaultRequest {
String response = new HttpUtils(config.getHttpConfig()).get(UrlBuilder.fromBaseUrl(source.userInfo())
.queryParam("access_token", authToken.getAccessToken())
.queryParam("open_id", openId)
.build());
.build()).getBody();
JSONObject object = JSONObject.parseObject(response);
if (!"0".equals(object.getString("c"))) {
throw new AuthException(object.getString("m"));
@@ -103,14 +103,14 @@ public class AuthKujialeRequest extends AuthDefaultRequest {
private String getOpenId(AuthToken authToken) {
String response = new HttpUtils(config.getHttpConfig()).get(UrlBuilder.fromBaseUrl("https://oauth.kujiale.com/oauth2/auth/user")
.queryParam("access_token", authToken.getAccessToken())
.build());
.build()).getBody();
JSONObject accessTokenObject = checkResponse(response);
return accessTokenObject.getString("d");
}
@Override
public AuthResponse refresh(AuthToken authToken) {
String response = new HttpUtils(config.getHttpConfig()).post(refreshTokenUrl(authToken.getRefreshToken()));
String response = new HttpUtils(config.getHttpConfig()).post(refreshTokenUrl(authToken.getRefreshToken())).getBody();
return AuthResponse.builder().code(AuthResponseStatus.SUCCESS.getCode()).data(getAuthToken(response)).build();
}
}
@@ -0,0 +1,126 @@
package me.zhyd.oauth.request;
import com.alibaba.fastjson.JSONObject;
import com.xkcoding.http.support.HttpHeader;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.config.AuthDefaultSource;
import me.zhyd.oauth.enums.AuthResponseStatus;
import me.zhyd.oauth.enums.AuthUserGender;
import me.zhyd.oauth.enums.scope.AuthLineScope;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.utils.AuthScopeUtils;
import me.zhyd.oauth.utils.HttpUtils;
import me.zhyd.oauth.utils.UrlBuilder;
import java.util.HashMap;
import java.util.Map;
/**
* LINE 登录, line.biz
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @since 1.16.0
*/
public class AuthLineRequest extends AuthDefaultRequest {
public AuthLineRequest(AuthConfig config) {
super(config, AuthDefaultSource.LINE);
}
public AuthLineRequest(AuthConfig config, AuthStateCache authStateCache) {
super(config, AuthDefaultSource.LINE, authStateCache);
}
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
Map<String, String> params = new HashMap<>();
params.put("grant_type", "authorization_code");
params.put("code", authCallback.getCode());
params.put("redirect_uri", config.getRedirectUri());
params.put("client_id", config.getClientId());
params.put("client_secret", config.getClientSecret());
String response = new HttpUtils(config.getHttpConfig()).post(source.accessToken(), params, false).getBody();
JSONObject accessTokenObject = JSONObject.parseObject(response);
return AuthToken.builder()
.accessToken(accessTokenObject.getString("access_token"))
.refreshToken(accessTokenObject.getString("refresh_token"))
.expireIn(accessTokenObject.getIntValue("expires_in"))
.idToken(accessTokenObject.getString("id_token"))
.scope(accessTokenObject.getString("scope"))
.tokenType(accessTokenObject.getString("token_type"))
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String userInfo = new HttpUtils(config.getHttpConfig()).get(source.userInfo(), null, new HttpHeader()
.add("Content-Type", "application/x-www-form-urlencoded")
.add("Authorization", "Bearer ".concat(authToken.getAccessToken())), false).getBody();
JSONObject object = JSONObject.parseObject(userInfo);
return AuthUser.builder()
.rawUserInfo(object)
.uuid(object.getString("userId"))
.username(object.getString("displayName"))
.nickname(object.getString("displayName"))
.avatar(object.getString("pictureUrl"))
.remark(object.getString("statusMessage"))
.gender(AuthUserGender.UNKNOWN)
.token(authToken)
.source(source.toString())
.build();
}
@Override
public AuthResponse revoke(AuthToken authToken) {
Map<String, String> params = new HashMap<>(5);
params.put("access_token", authToken.getAccessToken());
params.put("client_id", config.getClientId());
params.put("client_secret", config.getClientSecret());
String userInfo = new HttpUtils(config.getHttpConfig()).post(source.revoke(), params, false).getBody();
JSONObject object = JSONObject.parseObject(userInfo);
// 返回1表示取消授权成功,否则失败
AuthResponseStatus status = object.getBooleanValue("revoked") ? AuthResponseStatus.SUCCESS : AuthResponseStatus.FAILURE;
return AuthResponse.builder().code(status.getCode()).msg(status.getMsg()).build();
}
@Override
public AuthResponse refresh(AuthToken oldToken) {
Map<String, String> params = new HashMap<>();
params.put("grant_type", "refresh_token");
params.put("refresh_token", oldToken.getRefreshToken());
params.put("client_id", config.getClientId());
params.put("client_secret", config.getClientSecret());
String response = new HttpUtils(config.getHttpConfig()).post(source.accessToken(), params, false).getBody();
JSONObject accessTokenObject = JSONObject.parseObject(response);
return AuthResponse.builder()
.code(AuthResponseStatus.SUCCESS.getCode())
.data(AuthToken.builder()
.accessToken(accessTokenObject.getString("access_token"))
.refreshToken(accessTokenObject.getString("refresh_token"))
.expireIn(accessTokenObject.getIntValue("expires_in"))
.idToken(accessTokenObject.getString("id_token"))
.scope(accessTokenObject.getString("scope"))
.tokenType(accessTokenObject.getString("token_type"))
.build())
.build();
}
@Override
public String userInfoUrl(AuthToken authToken) {
return UrlBuilder.fromBaseUrl(source.userInfo())
.queryParam("user", authToken.getUid())
.build();
}
@Override
public String authorize(String state) {
return UrlBuilder.fromBaseUrl(super.authorize(state))
.queryParam("nonce", state)
.queryParam("scope", this.getScopes(" ", true, AuthScopeUtils.getDefaultScopes(AuthLineScope.values())))
.build();
}
}
@@ -48,7 +48,7 @@ public class AuthLinkedinRequest extends AuthDefaultRequest {
httpHeader.add("Connection", "Keep-Alive");
httpHeader.add("Authorization", "Bearer " + accessToken);
String response = new HttpUtils(config.getHttpConfig()).get(userInfoUrl(authToken), null, httpHeader, false);
String response = new HttpUtils(config.getHttpConfig()).get(userInfoUrl(authToken), null, httpHeader, false).getBody();
JSONObject userInfoObject = JSONObject.parseObject(response);
this.checkResponse(userInfoObject);
@@ -138,7 +138,9 @@ public class AuthLinkedinRequest extends AuthDefaultRequest {
httpHeader.add("Connection", "Keep-Alive");
httpHeader.add("Authorization", "Bearer " + accessToken);
String emailResponse = new HttpUtils(config.getHttpConfig()).get("https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))", null, httpHeader, false);
String emailResponse = new HttpUtils(config.getHttpConfig())
.get("https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))", null, httpHeader, false)
.getBody();
JSONObject emailObj = JSONObject.parseObject(emailResponse);
this.checkResponse(emailObj);
@@ -178,7 +180,7 @@ public class AuthLinkedinRequest extends AuthDefaultRequest {
httpHeader.add("Host", "www.linkedin.com");
httpHeader.add(Constants.CONTENT_TYPE, "application/x-www-form-urlencoded");
String response = new HttpUtils(config.getHttpConfig()).post(accessTokenUrl, null, httpHeader);
String response = new HttpUtils(config.getHttpConfig()).post(accessTokenUrl, null, httpHeader).getBody();
JSONObject accessTokenObject = JSONObject.parseObject(response);
this.checkResponse(accessTokenObject);
@@ -35,13 +35,13 @@ public class AuthMeituanRequest extends AuthDefaultRequest {
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
Map<String, String> form = new HashMap<>(4);
Map<String, String> form = new HashMap<>(7);
form.put("app_id", config.getClientId());
form.put("secret", config.getClientSecret());
form.put("code", authCallback.getCode());
form.put("grant_type", "authorization_code");
String response = new HttpUtils(config.getHttpConfig()).post(source.accessToken(), form, false);
String response = new HttpUtils(config.getHttpConfig()).post(source.accessToken(), form, false).getBody();
JSONObject object = JSONObject.parseObject(response);
this.checkResponse(object);
@@ -55,12 +55,12 @@ public class AuthMeituanRequest extends AuthDefaultRequest {
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
Map<String, String> form = new HashMap<>(3);
Map<String, String> form = new HashMap<>(5);
form.put("app_id", config.getClientId());
form.put("secret", config.getClientSecret());
form.put("access_token", authToken.getAccessToken());
String response = new HttpUtils(config.getHttpConfig()).post(source.userInfo(), form, false);
String response = new HttpUtils(config.getHttpConfig()).post(source.userInfo(), form, false).getBody();
JSONObject object = JSONObject.parseObject(response);
this.checkResponse(object);
@@ -79,13 +79,13 @@ public class AuthMeituanRequest extends AuthDefaultRequest {
@Override
public AuthResponse refresh(AuthToken oldToken) {
Map<String, String> form = new HashMap<>(4);
Map<String, String> form = new HashMap<>(7);
form.put("app_id", config.getClientId());
form.put("secret", config.getClientSecret());
form.put("refresh_token", oldToken.getRefreshToken());
form.put("grant_type", "refresh_token");
String response = new HttpUtils(config.getHttpConfig()).post(source.refresh(), form, false);
String response = new HttpUtils(config.getHttpConfig()).post(source.refresh(), form, false).getBody();
JSONObject object = JSONObject.parseObject(response);
this.checkResponse(object);
@@ -43,7 +43,7 @@ public class AuthMiRequest extends AuthDefaultRequest {
}
private AuthToken getToken(String accessTokenUrl) {
String response = new HttpUtils(config.getHttpConfig()).get(accessTokenUrl);
String response = new HttpUtils(config.getHttpConfig()).get(accessTokenUrl).getBody();
String jsonStr = response.replace(PREFIX, Constants.EMPTY);
JSONObject accessTokenObject = JSONObject.parseObject(jsonStr);
@@ -91,7 +91,7 @@ public class AuthMiRequest extends AuthDefaultRequest {
String emailPhoneUrl = MessageFormat.format("{0}?clientId={1}&token={2}", "https://open.account.xiaomi.com/user/phoneAndEmail", config
.getClientId(), authToken.getAccessToken());
String emailResponse = new HttpUtils(config.getHttpConfig()).get(emailPhoneUrl);
String emailResponse = new HttpUtils(config.getHttpConfig()).get(emailPhoneUrl).getBody();
JSONObject userEmailPhone = JSONObject.parseObject(emailResponse);
if (!"error".equalsIgnoreCase(userEmailPhone.getString("result"))) {
JSONObject emailPhone = userEmailPhone.getJSONObject("data");
@@ -0,0 +1,23 @@
package me.zhyd.oauth.request;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.config.AuthDefaultSource;
/**
* 微软中国登录(世纪华联)
*
* @author mroldx (xzfqq5201314@gmail.com)
* @since 1.16.4
*/
public class AuthMicrosoftCnRequest extends AbstractAuthMicrosoftRequest {
public AuthMicrosoftCnRequest(AuthConfig config) {
super(config, AuthDefaultSource.MICROSOFT_CN);
}
public AuthMicrosoftCnRequest(AuthConfig config, AuthStateCache authStateCache) {
super(config, AuthDefaultSource.MICROSOFT_CN, authStateCache);
}
}
@@ -1,32 +1,18 @@
package me.zhyd.oauth.request;
import com.alibaba.fastjson.JSONObject;
import com.xkcoding.http.support.HttpHeader;
import com.xkcoding.http.util.MapUtil;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.config.AuthDefaultSource;
import me.zhyd.oauth.enums.AuthResponseStatus;
import me.zhyd.oauth.enums.AuthUserGender;
import me.zhyd.oauth.enums.scope.AuthMicrosoftScope;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.utils.AuthScopeUtils;
import me.zhyd.oauth.utils.HttpUtils;
import me.zhyd.oauth.utils.UrlBuilder;
import java.util.Map;
/**
* 微软登录
* update 2021-08-24 mroldx (xzfqq5201314@gmail.com)
*
* @author yangkai.shen (https://xkcoding.com)
* @since 1.5.0
*/
public class AuthMicrosoftRequest extends AuthDefaultRequest {
public class AuthMicrosoftRequest extends AbstractAuthMicrosoftRequest {
public AuthMicrosoftRequest(AuthConfig config) {
super(config, AuthDefaultSource.MICROSOFT);
}
@@ -35,145 +21,4 @@ public class AuthMicrosoftRequest extends AuthDefaultRequest {
super(config, AuthDefaultSource.MICROSOFT, authStateCache);
}
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
return getToken(accessTokenUrl(authCallback.getCode()));
}
/**
* 获取token,适用于获取access_token和刷新token
*
* @param accessTokenUrl 实际请求token的地址
* @return token对象
*/
private AuthToken getToken(String accessTokenUrl) {
HttpHeader httpHeader = new HttpHeader();
Map<String, String> form = MapUtil.parseStringToMap(accessTokenUrl, false);
String response = new HttpUtils(config.getHttpConfig()).post(accessTokenUrl, form, httpHeader, false);
JSONObject accessTokenObject = JSONObject.parseObject(response);
this.checkResponse(accessTokenObject);
return AuthToken.builder()
.accessToken(accessTokenObject.getString("access_token"))
.expireIn(accessTokenObject.getIntValue("expires_in"))
.scope(accessTokenObject.getString("scope"))
.tokenType(accessTokenObject.getString("token_type"))
.refreshToken(accessTokenObject.getString("refresh_token"))
.build();
}
/**
* 检查响应内容是否正确
*
* @param object 请求响应内容
*/
private void checkResponse(JSONObject object) {
if (object.containsKey("error")) {
throw new AuthException(object.getString("error_description"));
}
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
String token = authToken.getAccessToken();
String tokenType = authToken.getTokenType();
String jwt = tokenType + " " + token;
HttpHeader httpHeader = new HttpHeader();
httpHeader.add("Authorization", jwt);
String userInfo = new HttpUtils(config.getHttpConfig()).get(userInfoUrl(authToken), null, httpHeader, false);
JSONObject object = JSONObject.parseObject(userInfo);
this.checkResponse(object);
return AuthUser.builder()
.rawUserInfo(object)
.uuid(object.getString("id"))
.username(object.getString("userPrincipalName"))
.nickname(object.getString("displayName"))
.location(object.getString("officeLocation"))
.email(object.getString("mail"))
.gender(AuthUserGender.UNKNOWN)
.token(authToken)
.source(source.toString())
.build();
}
/**
* 刷新access token (续期)
*
* @param authToken 登录成功后返回的Token信息
* @return AuthResponse
*/
@Override
public AuthResponse refresh(AuthToken authToken) {
return AuthResponse.builder()
.code(AuthResponseStatus.SUCCESS.getCode())
.data(getToken(refreshTokenUrl(authToken.getRefreshToken())))
.build();
}
/**
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
* @since 1.9.3
*/
@Override
public String authorize(String state) {
return UrlBuilder.fromBaseUrl(super.authorize(state))
.queryParam("response_mode", "query")
.queryParam("scope", this.getScopes(" ", true, AuthScopeUtils.getDefaultScopes(AuthMicrosoftScope.values())))
.build();
}
/**
* 返回获取accessToken的url
*
* @param code 授权code
* @return 返回获取accessToken的url
*/
@Override
protected String accessTokenUrl(String code) {
return UrlBuilder.fromBaseUrl(source.accessToken())
.queryParam("code", code)
.queryParam("client_id", config.getClientId())
.queryParam("client_secret", config.getClientSecret())
.queryParam("grant_type", "authorization_code")
.queryParam("scope", this.getScopes(" ", true, AuthScopeUtils.getDefaultScopes(AuthMicrosoftScope.values())))
.queryParam("redirect_uri", config.getRedirectUri())
.build();
}
/**
* 返回获取userInfo的url
*
* @param authToken 用户授权后的token
* @return 返回获取userInfo的url
*/
@Override
protected String userInfoUrl(AuthToken authToken) {
return UrlBuilder.fromBaseUrl(source.userInfo()).build();
}
/**
* 返回获取accessToken的url
*
* @param refreshToken 用户授权后的token
* @return 返回获取accessToken的url
*/
@Override
protected String refreshTokenUrl(String refreshToken) {
return UrlBuilder.fromBaseUrl(source.refresh())
.queryParam("client_id", config.getClientId())
.queryParam("client_secret", config.getClientSecret())
.queryParam("refresh_token", refreshToken)
.queryParam("grant_type", "refresh_token")
.queryParam("scope", this.getScopes(" ", true, AuthScopeUtils.getDefaultScopes(AuthMicrosoftScope.values())))
.queryParam("redirect_uri", config.getRedirectUri())
.build();
}
}
@@ -0,0 +1,159 @@
package me.zhyd.oauth.request;
import com.alibaba.fastjson.JSONObject;
import com.xkcoding.http.support.HttpHeader;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.config.AuthDefaultSource;
import me.zhyd.oauth.enums.AuthResponseStatus;
import me.zhyd.oauth.enums.AuthUserGender;
import me.zhyd.oauth.enums.scope.AuthOktaScope;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.utils.AuthScopeUtils;
import me.zhyd.oauth.utils.Base64Utils;
import me.zhyd.oauth.utils.HttpUtils;
import me.zhyd.oauth.utils.UrlBuilder;
import java.util.HashMap;
import java.util.Map;
/**
* Okta 登录
* <p>
* https://{domainPrefix}.okta.com/oauth2/default/.well-known/oauth-authorization-server
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @since 1.16.0
*/
public class AuthOktaRequest extends AuthDefaultRequest {
public AuthOktaRequest(AuthConfig config) {
super(config, AuthDefaultSource.OKTA);
}
public AuthOktaRequest(AuthConfig config, AuthStateCache authStateCache) {
super(config, AuthDefaultSource.OKTA, authStateCache);
}
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
String tokenUrl = accessTokenUrl(authCallback.getCode());
return getAuthToken(tokenUrl);
}
private AuthToken getAuthToken(String tokenUrl) {
HttpHeader header = new HttpHeader()
.add("accept", "application/json")
.add("content-type", "application/x-www-form-urlencoded")
.add("Authorization", "Basic " + Base64Utils.encode(config.getClientId().concat(":").concat(config.getClientSecret())));
String response = new HttpUtils(config.getHttpConfig()).post(tokenUrl, null, header, false).getBody();
JSONObject accessTokenObject = JSONObject.parseObject(response);
this.checkResponse(accessTokenObject);
return AuthToken.builder()
.accessToken(accessTokenObject.getString("access_token"))
.tokenType(accessTokenObject.getString("token_type"))
.expireIn(accessTokenObject.getIntValue("expires_in"))
.scope(accessTokenObject.getString("scope"))
.refreshToken(accessTokenObject.getString("refresh_token"))
.idToken(accessTokenObject.getString("id_token"))
.build();
}
@Override
public AuthResponse refresh(AuthToken authToken) {
if (null == authToken.getRefreshToken()) {
return AuthResponse.builder()
.code(AuthResponseStatus.ILLEGAL_TOKEN.getCode())
.msg(AuthResponseStatus.ILLEGAL_TOKEN.getMsg())
.build();
}
String refreshUrl = refreshTokenUrl(authToken.getRefreshToken());
return AuthResponse.builder()
.code(AuthResponseStatus.SUCCESS.getCode())
.data(this.getAuthToken(refreshUrl))
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
HttpHeader header = new HttpHeader()
.add("Authorization", "Bearer " + authToken.getAccessToken());
String response = new HttpUtils(config.getHttpConfig()).post(userInfoUrl(authToken), null, header, false).getBody();
JSONObject object = JSONObject.parseObject(response);
this.checkResponse(object);
JSONObject address = object.getJSONObject("address");
return AuthUser.builder()
.rawUserInfo(object)
.uuid(object.getString("sub"))
.username(object.getString("name"))
.nickname(object.getString("nickname"))
.email(object.getString("email"))
.location(null == address ? null : address.getString("street_address"))
.gender(AuthUserGender.getRealGender(object.getString("sex")))
.token(authToken)
.source(source.toString())
.build();
}
@Override
public AuthResponse revoke(AuthToken authToken) {
Map<String, String> params = new HashMap<>(4);
params.put("token", authToken.getAccessToken());
params.put("token_type_hint", "access_token");
HttpHeader header = new HttpHeader()
.add("Authorization", "Basic " + Base64Utils.encode(config.getClientId().concat(":").concat(config.getClientSecret())));
new HttpUtils(config.getHttpConfig()).post(revokeUrl(authToken), params, header, false);
AuthResponseStatus status = AuthResponseStatus.SUCCESS;
return AuthResponse.builder().code(status.getCode()).msg(status.getMsg()).build();
}
private void checkResponse(JSONObject object) {
if (object.containsKey("error")) {
throw new AuthException(object.getString("error_description"));
}
}
@Override
public String authorize(String state) {
return UrlBuilder.fromBaseUrl(String.format(source.authorize(), config.getDomainPrefix(), config.getAuthServerId()))
.queryParam("response_type", "code")
.queryParam("prompt", "consent")
.queryParam("client_id", config.getClientId())
.queryParam("redirect_uri", config.getRedirectUri())
.queryParam("scope", this.getScopes(" ", true, AuthScopeUtils.getDefaultScopes(AuthOktaScope.values())))
.queryParam("state", getRealState(state))
.build();
}
@Override
public String accessTokenUrl(String code) {
return UrlBuilder.fromBaseUrl(String.format(source.accessToken(), config.getDomainPrefix(), config.getAuthServerId()))
.queryParam("code", code)
.queryParam("grant_type", "authorization_code")
.queryParam("redirect_uri", config.getRedirectUri())
.build();
}
@Override
protected String refreshTokenUrl(String refreshToken) {
return UrlBuilder.fromBaseUrl(String.format(source.refresh(), config.getDomainPrefix(), config.getAuthServerId()))
.queryParam("refresh_token", refreshToken)
.queryParam("grant_type", "refresh_token")
.build();
}
@Override
protected String revokeUrl(AuthToken authToken) {
return String.format(source.revoke(), config.getDomainPrefix(), config.getAuthServerId());
}
@Override
public String userInfoUrl(AuthToken authToken) {
return String.format(source.userInfo(), config.getDomainPrefix(), config.getAuthServerId());
}
}
@@ -50,7 +50,7 @@ public class AuthPinterestRequest extends AuthDefaultRequest {
protected AuthUser getUserInfo(AuthToken authToken) {
String userinfoUrl = userInfoUrl(authToken);
// TODO: 是否需要 .setFollowRedirects(true)
String response = new HttpUtils(config.getHttpConfig()).get(userinfoUrl);
String response = new HttpUtils(config.getHttpConfig()).get(userinfoUrl).getBody();
JSONObject object = JSONObject.parseObject(response);
this.checkResponse(object);
JSONObject userObj = object.getJSONObject("data");
@@ -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).getBody();
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();
}
}
@@ -40,7 +40,7 @@ public class AuthQqRequest extends AuthDefaultRequest {
@Override
public AuthResponse refresh(AuthToken authToken) {
String response = new HttpUtils(config.getHttpConfig()).get(refreshTokenUrl(authToken.getRefreshToken()));
String response = new HttpUtils(config.getHttpConfig()).get(refreshTokenUrl(authToken.getRefreshToken())).getBody();
return AuthResponse.builder().code(AuthResponseStatus.SUCCESS.getCode()).data(getAuthToken(response)).build();
}
@@ -82,7 +82,7 @@ public class AuthQqRequest extends AuthDefaultRequest {
String response = new HttpUtils(config.getHttpConfig()).get(UrlBuilder.fromBaseUrl("https://graph.qq.com/oauth2.0/me")
.queryParam("access_token", authToken.getAccessToken())
.queryParam("unionid", config.isUnionId() ? 1 : 0)
.build());
.build()).getBody();
String removePrefix = response.replace("callback(", "");
String removeSuffix = removePrefix.replace(");", "");
String openId = removeSuffix.trim();
@@ -68,7 +68,7 @@ public class AuthRenrenRequest extends AuthDefaultRequest {
}
private AuthToken getToken(String url) {
String response = new HttpUtils(config.getHttpConfig()).post(url);
String response = new HttpUtils(config.getHttpConfig()).post(url).getBody();
JSONObject jsonObject = JSONObject.parseObject(response);
if (jsonObject.containsKey("error")) {
throw new AuthException("Failed to get token from Renren: " + jsonObject);
@@ -0,0 +1,142 @@
package me.zhyd.oauth.request;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xkcoding.http.support.HttpHeader;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.config.AuthDefaultSource;
import me.zhyd.oauth.enums.AuthResponseStatus;
import me.zhyd.oauth.enums.AuthUserGender;
import me.zhyd.oauth.enums.scope.AuthSlackScope;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.utils.AuthScopeUtils;
import me.zhyd.oauth.utils.HttpUtils;
import me.zhyd.oauth.utils.UrlBuilder;
/**
* slack登录, slack.com
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @since 1.16.0
*/
public class AuthSlackRequest extends AuthDefaultRequest {
public AuthSlackRequest(AuthConfig config) {
super(config, AuthDefaultSource.SLACK);
}
public AuthSlackRequest(AuthConfig config, AuthStateCache authStateCache) {
super(config, AuthDefaultSource.SLACK, authStateCache);
}
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
HttpHeader header = new HttpHeader()
.add("Content-Type", "application/x-www-form-urlencoded");
String response = new HttpUtils(config.getHttpConfig())
.get(accessTokenUrl(authCallback.getCode()), null, header, false).getBody();
JSONObject accessTokenObject = JSONObject.parseObject(response);
this.checkResponse(accessTokenObject);
return AuthToken.builder()
.accessToken(accessTokenObject.getString("access_token"))
.scope(accessTokenObject.getString("scope"))
.tokenType(accessTokenObject.getString("token_type"))
.uid(accessTokenObject.getJSONObject("authed_user").getString("id"))
.build();
}
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
HttpHeader header = new HttpHeader()
.add("Content-Type", "application/x-www-form-urlencoded")
.add("Authorization", "Bearer ".concat(authToken.getAccessToken()));
String userInfo = new HttpUtils(config.getHttpConfig())
.get(userInfoUrl(authToken), null, header, false).getBody();
JSONObject object = JSONObject.parseObject(userInfo);
this.checkResponse(object);
JSONObject user = object.getJSONObject("user");
JSONObject profile = user.getJSONObject("profile");
return AuthUser.builder()
.rawUserInfo(user)
.uuid(user.getString("id"))
.username(user.getString("name"))
.nickname(user.getString("real_name"))
.avatar(profile.getString("image_original"))
.email(profile.getString("email"))
.gender(AuthUserGender.UNKNOWN)
.token(authToken)
.source(source.toString())
.build();
}
@Override
public AuthResponse revoke(AuthToken authToken) {
HttpHeader header = new HttpHeader()
.add("Content-Type", "application/x-www-form-urlencoded")
.add("Authorization", "Bearer ".concat(authToken.getAccessToken()));
String userInfo = new HttpUtils(config.getHttpConfig())
.get(source.revoke(), null, header, false).getBody();
JSONObject object = JSONObject.parseObject(userInfo);
this.checkResponse(object);
// 返回1表示取消授权成功,否则失败
AuthResponseStatus status = object.getBooleanValue("revoked") ? AuthResponseStatus.SUCCESS : AuthResponseStatus.FAILURE;
return AuthResponse.builder().code(status.getCode()).msg(status.getMsg()).build();
}
/**
* 检查响应内容是否正确
*
* @param object 请求响应内容
*/
private void checkResponse(JSONObject object) {
if (!object.getBooleanValue("ok")) {
String errorMsg = object.getString("error");
if (object.containsKey("response_metadata")) {
JSONArray array = object.getJSONObject("response_metadata").getJSONArray("messages");
if (null != array && array.size() > 0) {
errorMsg += "; " + String.join(",", array.toArray(new String[0]));
}
}
throw new AuthException(errorMsg);
}
}
@Override
public String userInfoUrl(AuthToken authToken) {
return UrlBuilder.fromBaseUrl(source.userInfo())
.queryParam("user", authToken.getUid())
.build();
}
/**
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
* @param state state 验证授权流程的参数,可以防止csrf
* @return 返回授权地址
*/
@Override
public String authorize(String state) {
return UrlBuilder.fromBaseUrl(source.authorize())
.queryParam("client_id", config.getClientId())
.queryParam("state", getRealState(state))
.queryParam("redirect_uri", config.getRedirectUri())
.queryParam("scope", this.getScopes(",", true, AuthScopeUtils.getDefaultScopes(AuthSlackScope.values())))
.build();
}
@Override
protected String accessTokenUrl(String code) {
return UrlBuilder.fromBaseUrl(source.accessToken())
.queryParam("code", code)
.queryParam("client_id", config.getClientId())
.queryParam("client_secret", config.getClientSecret())
.queryParam("redirect_uri", config.getRedirectUri())
.build();
}
}
@@ -42,7 +42,7 @@ public class AuthStackOverflowRequest extends AuthDefaultRequest {
Map<String, String> form = MapUtil.parseStringToMap(accessTokenUrl, false);
HttpHeader httpHeader = new HttpHeader();
httpHeader.add(Constants.CONTENT_TYPE, "application/x-www-form-urlencoded");
String response = new HttpUtils(config.getHttpConfig()).post(accessTokenUrl, form, httpHeader, false);
String response = new HttpUtils(config.getHttpConfig()).post(accessTokenUrl, form, httpHeader, false).getBody();
JSONObject accessTokenObject = JSONObject.parseObject(response);
this.checkResponse(accessTokenObject);
@@ -60,7 +60,7 @@ public class AuthStackOverflowRequest extends AuthDefaultRequest {
.queryParam("site", "stackoverflow")
.queryParam("key", this.config.getStackOverflowKey())
.build();
String response = new HttpUtils(config.getHttpConfig()).get(userInfoUrl);
String response = new HttpUtils(config.getHttpConfig()).get(userInfoUrl).getBody();
JSONObject object = JSONObject.parseObject(response);
this.checkResponse(object);
JSONObject userObj = object.getJSONArray("items").getJSONObject(0);
@@ -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).getBody();
JSONObject accessTokenObject = JSONObject.parseObject(response);
return AuthResponse.builder()
.code(AuthResponseStatus.SUCCESS.getCode())
.data(this.getAuthToken(accessTokenObject))
.build();
}
/**
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
*
@@ -39,13 +39,13 @@ public class AuthTeambitionRequest extends AuthDefaultRequest {
*/
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
Map<String, String> form = new HashMap<>(4);
Map<String, String> form = new HashMap<>(7);
form.put("client_id", config.getClientId());
form.put("client_secret", config.getClientSecret());
form.put("code", authCallback.getCode());
form.put("grant_type", "code");
String response = new HttpUtils(config.getHttpConfig()).post(source.accessToken(), form, false);
String response = new HttpUtils(config.getHttpConfig()).post(source.accessToken(), form, false).getBody();
JSONObject accessTokenObject = JSONObject.parseObject(response);
this.checkResponse(accessTokenObject);
@@ -63,7 +63,8 @@ public class AuthTeambitionRequest extends AuthDefaultRequest {
HttpHeader httpHeader = new HttpHeader();
httpHeader.add("Authorization", "OAuth2 " + accessToken);
String response = new HttpUtils(config.getHttpConfig()).get(source.userInfo(), null, httpHeader, false);
String response = new HttpUtils(config.getHttpConfig())
.get(source.userInfo(), null, httpHeader, false).getBody();
JSONObject object = JSONObject.parseObject(response);
this.checkResponse(object);
@@ -90,10 +91,10 @@ public class AuthTeambitionRequest extends AuthDefaultRequest {
String uid = oldToken.getUid();
String refreshToken = oldToken.getRefreshToken();
Map<String, String> form = new HashMap<>(2);
Map<String, String> form = new HashMap<>(4);
form.put("_userId", uid);
form.put("refresh_token", refreshToken);
String response = new HttpUtils(config.getHttpConfig()).post(source.refresh(), form, false);
String response = new HttpUtils(config.getHttpConfig()).post(source.refresh(), form, false).getBody();
JSONObject refreshTokenObject = JSONObject.parseObject(response);
this.checkResponse(refreshTokenObject);
@@ -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();
@@ -69,10 +69,8 @@ public class AuthTwitterRequest extends AuthDefaultRequest {
HttpHeader httpHeader = new HttpHeader();
httpHeader.add("Authorization", header);
httpHeader.add("User-Agent", "themattharris' HTTP Client");
httpHeader.add("Host", "api.twitter.com");
httpHeader.add("Accept", "*/*");
String requestToken = new HttpUtils(config.getHttpConfig()).post(baseUrl, null, httpHeader);
httpHeader.add("User-Agent", "'JustAuth' HTTP Client Simple-Http");
String requestToken = new HttpUtils(config.getHttpConfig()).post(baseUrl, null, httpHeader).getBody();
Map<String, String> res = MapUtil.parseStringToMap(requestToken, false);
@@ -102,9 +100,9 @@ public class AuthTwitterRequest extends AuthDefaultRequest {
httpHeader.add("Authorization", header);
httpHeader.add(Constants.CONTENT_TYPE, "application/x-www-form-urlencoded");
Map<String, String> form = new HashMap<>(1);
Map<String, String> form = new HashMap<>(3);
form.put("oauth_verifier", authCallback.getOauth_verifier());
String response = new HttpUtils(config.getHttpConfig()).post(source.accessToken(), form, httpHeader, false);
String response = new HttpUtils(config.getHttpConfig()).post(source.accessToken(), form, httpHeader, false).getBody();
Map<String, String> requestToken = MapUtil.parseStringToMap(response, false);
@@ -118,23 +116,22 @@ public class AuthTwitterRequest extends AuthDefaultRequest {
@Override
protected AuthUser getUserInfo(AuthToken authToken) {
Map<String, String> queryParams = new HashMap<>();
queryParams.put("user_id", authToken.getUserId());
queryParams.put("screen_name", authToken.getScreenName());
Map<String, String> queryParams = new HashMap<>(5);
queryParams.put("include_entities", Boolean.toString(true));
queryParams.put("include_email", Boolean.toString(true));
Map<String, String> oauthParams = buildOauthParams();
oauthParams.put("oauth_token", authToken.getOauthToken());
Map<String, String> params = new HashMap<>(oauthParams);
params.putAll(queryParams);
oauthParams.put("oauth_signature", generateTwitterSignature(params, "GET", source.userInfo(), config.getClientSecret(), authToken
.getOauthTokenSecret()));
oauthParams.put("oauth_signature", generateTwitterSignature(params, "GET", source.userInfo(), config.getClientSecret(), authToken.getOauthTokenSecret()));
String header = buildHeader(oauthParams);
HttpHeader httpHeader = new HttpHeader();
httpHeader.add("Authorization", header);
String response = new HttpUtils(config.getHttpConfig()).get(userInfoUrl(authToken), null, httpHeader, false);
String response = new HttpUtils(config.getHttpConfig())
.get(userInfoUrl(authToken), null, httpHeader, false).getBody();
JSONObject userInfo = JSONObject.parseObject(response);
return AuthUser.builder()
@@ -147,6 +144,7 @@ public class AuthTwitterRequest extends AuthDefaultRequest {
.blog(userInfo.getString("url"))
.location(userInfo.getString("location"))
.avatar(userInfo.getString("profile_image_url"))
.email(userInfo.getString("email"))
.source(source.toString())
.token(authToken)
.build();
@@ -155,14 +153,13 @@ public class AuthTwitterRequest extends AuthDefaultRequest {
@Override
protected String userInfoUrl(AuthToken authToken) {
return UrlBuilder.fromBaseUrl(source.userInfo())
.queryParam("user_id", authToken.getUserId())
.queryParam("screen_name", authToken.getScreenName())
.queryParam("include_entities", true)
.queryParam("include_email", true)
.build();
}
private Map<String, String> buildOauthParams() {
Map<String, String> params = new HashMap<>(5);
Map<String, String> params = new HashMap<>(12);
params.put("oauth_consumer_key", config.getClientId());
params.put("oauth_nonce", GlobalAuthUtils.generateNonce(32));
params.put("oauth_signature_method", "HMAC-SHA1");

Some files were not shown because too many files have changed in this diff Show More