├── .github
└── workflows
│ ├── build.yml
│ └── publish.yml
├── .gitignore
├── LICENSE
├── README.md
├── build.gradle
├── flows-amazon
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── hanbings
│ └── flows
│ └── amazon
│ ├── AmazonAccess.java
│ ├── AmazonIdentify.java
│ ├── AmazonOAuth.java
│ └── AmazonProfile.java
├── flows-baidu
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── hanbings
│ └── flows
│ └── baidu
│ ├── BaiduAccess.java
│ ├── BaiduIdentify.java
│ ├── BaiduOAuth.java
│ └── BaiduProfile.java
├── flows-common
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── hanbings
│ └── flows
│ └── common
│ ├── OAuth.java
│ ├── OAuthCallback.java
│ ├── OAuthRequest.java
│ ├── OAuthResponse.java
│ ├── OAuthSerialization.java
│ ├── OAuthState.java
│ ├── exception
│ └── NoResponseReceivedException.java
│ ├── function
│ └── Lazy.java
│ └── interfaces
│ ├── Access.java
│ ├── Accessible.java
│ ├── Callback.java
│ ├── Identifiable.java
│ ├── Identify.java
│ ├── Profilable.java
│ ├── Profile.java
│ ├── Refresh.java
│ ├── Refreshable.java
│ ├── Request.java
│ ├── Response.java
│ ├── Revokable.java
│ ├── Revoke.java
│ ├── Serialization.java
│ └── State.java
├── flows-discord
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── hanbings
│ └── flows
│ └── discord
│ ├── DiscordAccess.java
│ ├── DiscordIdentify.java
│ ├── DiscordOAuth.java
│ ├── DiscordProfile.java
│ └── DiscordRevoke.java
├── flows-dropbox
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── hanbings
│ └── flows
│ └── dropbox
│ ├── DropboxAccess.java
│ ├── DropboxOAuth.java
│ ├── DropboxRefresh.java
│ └── DropboxRevoke.java
├── flows-ebay
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── hanbings
│ └── flows
│ └── ebay
│ ├── EbayAccess.java
│ ├── EbayIdentify.java
│ ├── EbayOAuth.java
│ └── EbayProfile.java
├── flows-etsy
└── build.gradle
├── flows-extra
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── hanbings
│ └── flows
│ └── extra
│ └── OkhttpRequest.java
├── flows-facebook
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── hanbings
│ └── flows
│ └── facebook
│ ├── FacebookAccess.java
│ └── FacebookOAuth.java
├── flows-flickr
└── build.gradle
├── flows-github
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── hanbings
│ └── flows
│ └── github
│ ├── GithubAccess.java
│ ├── GithubIdentify.java
│ ├── GithubOAuth.java
│ └── GithubProfile.java
├── flows-gitlab
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── hanbings
│ └── flows
│ └── gitlab
│ ├── GitlabAccess.java
│ ├── GitlabIdentify.java
│ ├── GitlabOAuth.java
│ └── GitlabProfile.java
├── flows-google
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── hanbings
│ └── flows
│ └── google
│ ├── GoogleAccess.java
│ ├── GoogleIdentify.java
│ ├── GoogleOAuth.java
│ ├── GoogleProfile.java
│ └── GoogleRevoke.java
├── flows-imgur
└── build.gradle
├── flows-instagram
└── build.gradle
├── flows-line
└── build.gradle
├── flows-microsoft
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── hanbings
│ └── flows
│ └── microsoft
│ ├── MicrosoftAccess.java
│ ├── MicrosoftCommonOAuth.java
│ ├── MicrosoftConsumersOAuth.java
│ ├── MicrosoftIdentify.java
│ ├── MicrosoftOAuth.java
│ ├── MicrosoftOrganizationsOAuth.java
│ ├── MicrosoftProfile.java
│ └── MicrosoftRevoke.java
├── flows-pinterest
└── build.gradle
├── flows-qq
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── hanbings
│ └── flows
│ └── qq
│ ├── QQAccess.java
│ ├── QQIdentify.java
│ ├── QQOAuth.java
│ └── QQProfile.java
├── flows-reddit
└── build.gradle
├── flows-soundcloud
└── build.gradle
├── flows-spotify
└── build.gradle
├── flows-stackoverflow
└── build.gradle
├── flows-tiktok
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── hanbings
│ └── flows
│ └── tiktok
│ ├── TiktokAccess.java
│ ├── TiktokIdentify.java
│ ├── TiktokOAuth.java
│ └── TiktokProfile.java
├── flows-tumblr
└── build.gradle
├── flows-twitch
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── hanbings
│ └── flows
│ └── twitch
│ ├── TwitchAccess.java
│ ├── TwitchIdentify.java
│ ├── TwitchOAuth.java
│ └── TwitchProfile.java
├── flows-twitter
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── hanbings
│ └── flows
│ └── twitter
│ ├── TwitterAccess.java
│ ├── TwitterIdentify.java
│ ├── TwitterOAuth.java
│ └── TwitterProfile.java
├── flows-weibo
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── hanbings
│ └── flows
│ └── weibo
│ ├── WeiboAccess.java
│ ├── WeiboIdentify.java
│ ├── WeiboOAuth.java
│ ├── WeiboProfile.java
│ └── WeiboRevoke.java
├── flows-wordpress
├── build.gradle
└── src
│ └── main
│ └── java
│ └── io
│ └── hanbings
│ └── flows
│ └── wordpress
│ ├── WordpressAccess.java
│ ├── WordpressIdentify.java
│ ├── WordpressOAuth.java
│ └── WordpressProfile.java
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Flows Build
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 | if: "! contains(github.event.head_commit.message, '#Skip')"
13 | steps:
14 | - uses: actions/checkout@v3
15 |
16 | - name: Set up JDK 17
17 | uses: actions/setup-java@v3
18 | with:
19 | java-version: 17
20 | distribution: adopt
21 |
22 | - name: Grant execute permission for gradlew
23 | run: chmod +x gradlew
24 |
25 | - name: Build with Gradle (build project)
26 | run: ./gradlew build -x test
27 |
28 | - name: Build with Gradle (shadow)
29 | run: ./gradlew shadowJar
30 |
31 | - name: Build with Gradle (collect)
32 | run: ./gradlew collect
33 |
34 | - uses: actions/upload-artifact@v3
35 | with:
36 | name: build
37 | path: build/libs
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Flows Publish
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 |
7 | jobs:
8 | publish:
9 | runs-on: ubuntu-latest
10 | if: "! contains(github.event.head_commit.message, '#Skip')"
11 | steps:
12 | - uses: actions/checkout@v3
13 |
14 | - name: Fetch commit hash
15 | id: sha
16 | if: "! contains(github.event.head_commit.message, '#Release')"
17 | run: |
18 | sha=$(git rev-parse --short ${{ github.sha }})
19 | echo "::set-output name=short_sha::$sha"
20 |
21 | - name: Replace publish version
22 | if: "! contains(github.event.head_commit.message, '#Release')"
23 | uses: Nambers/ReplaceStringInFile@v1.1
24 | with:
25 | path: ${{ github.workspace }}/build.gradle
26 | oldString: '@{{COMMIT_SHORT_SHA}}'
27 | newString: ${{ steps.sha.outputs.short_sha }}
28 |
29 | - name: Set up JDK 17
30 | uses: actions/setup-java@v3
31 | with:
32 | java-version: 17
33 | distribution: adopt
34 |
35 | - name: Grant execute permission for gradlew
36 | run: chmod +x gradlew
37 |
38 | - name: Build with Gradle (build)
39 | run: ./gradlew build -x test
40 |
41 | - name: Build with Gradle (publish)
42 | run: ./gradlew publish
43 | env:
44 | REPOSITORY_ROOT_URL: ${{ secrets.REPOSITORY_ROOT_URL }}
45 | REPOSITORY_USER: ${{ secrets.REPOSITORY_USER }}
46 | REPOSITORY_TOKEN: ${{ secrets.REPOSITORY_TOKEN }}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # User-specific stuff
2 | .idea/
3 |
4 | *.iml
5 | *.ipr
6 | *.iws
7 |
8 | # IntelliJ
9 | out/
10 | # mpeltonen/sbt-idea plugin
11 | .idea_modules/
12 |
13 | # JIRA plugin
14 | atlassian-ide-plugin.xml
15 |
16 | # Compiled class file
17 | *.class
18 |
19 | # Log file
20 | *.log
21 |
22 | # BlueJ files
23 | *.ctxt
24 |
25 | # Package Files #
26 | *.war
27 | *.nar
28 | *.ear
29 | *.zip
30 | *.tar.gz
31 | *.rar
32 |
33 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
34 | hs_err_pid*
35 |
36 | *~
37 |
38 | # temporary files which can be created if a process still has a handle open of a deleted file
39 | .fuse_hidden*
40 |
41 | # KDE directory preferences
42 | .directory
43 |
44 | # Linux trash folder which might appear on any partition or disk
45 | .Trash-*
46 |
47 | # .nfs files are created when an open file is removed but is still being accessed
48 | .nfs*
49 |
50 | # General
51 | .DS_Store
52 | .AppleDouble
53 | .LSOverride
54 |
55 | # Icon must end with two \r
56 | Icon
57 |
58 | # Thumbnails
59 | ._*
60 |
61 | # Files that might appear in the root of a volume
62 | .DocumentRevisions-V100
63 | .fseventsd
64 | .Spotlight-V100
65 | .TemporaryItems
66 | .Trashes
67 | .VolumeIcon.icns
68 | .com.apple.timemachine.donotpresent
69 |
70 | # Directories potentially created on remote AFP share
71 | .AppleDB
72 | .AppleDesktop
73 | Network Trash Folder
74 | Temporary Items
75 | .apdisk
76 |
77 | # Windows thumbnail cache files
78 | Thumbs.db
79 | Thumbs.db:encryptable
80 | ehthumbs.db
81 | ehthumbs_vista.db
82 |
83 | # Dump file
84 | *.stackdump
85 |
86 | # Folder config file
87 | [Dd]esktop.ini
88 |
89 | # Recycle Bin used on file shares
90 | $RECYCLE.BIN/
91 |
92 | # Windows Installer files
93 | *.cab
94 | *.msi
95 | *.msix
96 | *.msm
97 | *.msp
98 |
99 | # Windows shortcuts
100 | *.lnk
101 |
102 | .gradle
103 | build/
104 |
105 | # Ignore Gradle GUI config
106 | gradle-app.setting
107 |
108 | # Cache of project
109 | .gradletasknamecache
110 |
111 | **/build/
112 |
113 | # Common working directory
114 | run/
115 |
116 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
117 | !gradle-wrapper.jar
118 | gradle.properties
119 | repo/
120 |
121 | # logs directory
122 | logs/
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 |
🌊 Flows
4 | 海纳百川 有容乃大!
5 |
6 | ## 🍀 这是什么?
7 |
8 | **洋流**是一条 OAuth 客户端的辅助工具,通过低耦合的设计给用户高自定义度的接口,并且洋流集成了常见 OAuth 平台的封装,提供了光速集成第三方登录的能力。
9 |
10 | **洋流**的主要特性如下:
11 |
12 | - 常见的 OAuth 平台适配
13 | - 支持自定义 State 生成器、自定义 Http 客户端、自定义 Json 解析器
14 | - 提供通用默认实现以便支持未适配 OAuth 平台
15 | - 默认 Http 客户端实现支持 Socks 代理
16 | - 可爱
17 |
18 |
19 |
20 | **Github OAuth 示例**
21 |
22 | 洋流提供了许多的重载方法,用于应对不同情况下的请求,有些带自有请求头的,也有要求必须要 Scope 的。
23 |
24 | ```java
25 | // 创建 OAuth 原始处理器
26 | OAuth oauth = new GithubOAuth(
27 | "id",
28 | "secret",
29 | "https://exmaple.com/api/v0/login/oauth/github/callback"
30 | );
31 |
32 | // 生成授权 url
33 | String url = oauth.authorize();
34 | // 生成带参数或指定 scope
35 | String spec = oauth.authorize(List.of("email"), Map.of("Accept", "application/json"));
36 |
37 | //解析回调的 url 并获取 token
38 | // 输入原始 url 自动解析 code 以及 state
39 | oauth.token("url");
40 | // 更改回调地址
41 | oauth.token("url", "redirect");
42 | // 手动指定参数
43 | oauth.token("code", "state", "redirect");
44 |
45 | // 处理返回值
46 | oauth.token("code", "state", "redirect")
47 | .succeed(data -> System.out.println(data.accessToken()))
48 | .fail(wrong -> System.out.println(wrong.errorDescription()))
49 | .except(throwable -> System.out.println(throwable.getMessage()));
50 |
51 | // 假设请求成功 直接获取数据
52 | GithubAccess access = oauth.token("code", "state", "redirect").data();
53 | ```
54 |
55 | **使用 Socks 代理**
56 |
57 | ```java
58 | oauth.proxy(() ->
59 | new Request.Proxy(
60 | Proxy.Type.SOCKS,
61 | "127.0.0.1",
62 | 10086,
63 | "username",
64 | "password"
65 | )
66 | );
67 | ```
68 |
69 | **更换 State 生成器**
70 |
71 | 默认随机生成 UUID 并设置 300 秒有效期
72 |
73 | ```java
74 | oauth.state(
75 | Lazy.of(() -> new OAuthState(300, () -> UUID.randomUUID().toString()))
76 | );
77 | ```
78 |
79 | **更换 Http 客户端**
80 |
81 | 默认使用 `java.net.http` 的 HttpClient 发起请求,无需任何第三方依赖,在 `flows-extra` 中还有一个 Okhttp 的实现
82 |
83 | ```java
84 | // 实现比较繁杂 就不展示啦 x
85 | oauth.request(
86 | Lazy.of(() -> proxy == null ? new OAuthRequest() : new OAuthRequest(proxy.get()))
87 | );
88 | ```
89 |
90 | **更换 Json 解析器**
91 |
92 | 默认使用 Gson 作为 Json 解析器
93 |
94 | ```java
95 | oauth.serialization(
96 | Lazy.of(() -> new Serialization() {
97 | final Gson gson = new Gson();
98 |
99 | @Override
100 | public T object(Class type, String raw) {
101 | return gson.fromJson(raw, type);
102 | }
103 |
104 | @Override
105 | public Map map(Class key, Class value, String raw) {
106 | return gson.fromJson(raw, new TypeToken