From 6cc424218c85fb3016296e3f079179c8956c05e2 Mon Sep 17 00:00:00 2001 From: songquanpeng Date: Tue, 3 Dec 2024 19:03:41 +0800 Subject: [PATCH] feat: add Feishu & Lark support --- README.md | 2 + .../com/github/scribejava/apis/FeishuApi.java | 41 ++++++++++ .../com/github/scribejava/apis/LarkApi.java | 41 ++++++++++ .../apis/examples/FeishuExample.java | 81 +++++++++++++++++++ .../scribejava/apis/examples/LarkExample.java | 81 +++++++++++++++++++ 5 files changed, 246 insertions(+) create mode 100644 scribejava-apis/src/main/java/com/github/scribejava/apis/FeishuApi.java create mode 100644 scribejava-apis/src/main/java/com/github/scribejava/apis/LarkApi.java create mode 100644 scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FeishuExample.java create mode 100644 scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LarkExample.java diff --git a/README.md b/README.md index b90ef2e5f..cf479761b 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ ScribeJava support out-of-box several HTTP clients: * Dropbox (https://www.dropbox.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/DropboxExample.java) * Etsy (https://www.etsy.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/EtsyExample.java) * Facebook (https://www.facebook.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FacebookExample.java), [example with Async Apache HTTP client](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FacebookAsyncApacheExample.java), [example with Async Ning HTTP client](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FacebookAsyncNingExample.java) +* Feishu 飞书 (https://www.feishu.cn/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FeishuExample.java) * Fitbit (https://www.fitbit.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FitbitApi20Example.java) * Flickr (https://www.flickr.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FlickrExample.java) * Foursquare (https://foursquare.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Foursquare2Example.java), [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FoursquareExample.java) @@ -81,6 +82,7 @@ ScribeJava support out-of-box several HTTP clients: * Kaixin 开心网 (http://www.kaixin001.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/Kaixin20Example.java) * Kakao (https://kakao.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/KakaoExample.java) * Keycloak (https://www.keycloak.org/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/KeycloakExample.java) +* Lark (https://www.larksuite.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LarkExample.java) * LinkedIn (https://www.linkedin.com/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LinkedIn20Example.java), [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LinkedInExample.java), [example with custom scopes](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LinkedInExampleWithScopes.java) * Mail.Ru (https://mail.ru/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MailruExample.java), [example with Async Ning HTTP Client](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MailruAsyncExample.java) * MediaWiki (https://www.mediawiki.org/) [example](https://github.com/scribejava/scribejava/blob/master/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/MediaWikiExample.java) diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/FeishuApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/FeishuApi.java new file mode 100644 index 000000000..d5b85885f --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/FeishuApi.java @@ -0,0 +1,41 @@ +package com.github.scribejava.apis; + +import com.github.scribejava.core.builder.api.DefaultApi20; +import com.github.scribejava.core.extractors.OAuth2AccessTokenExtractor; +import com.github.scribejava.core.extractors.TokenExtractor; +import com.github.scribejava.core.model.OAuth2AccessToken; +import com.github.scribejava.core.model.Verb; + +public class FeishuApi extends DefaultApi20 { + + protected FeishuApi() { + } + + private static class InstanceHolder { + private static final FeishuApi INSTANCE = new FeishuApi(); + } + + public static FeishuApi instance() { + return InstanceHolder.INSTANCE; + } + + @Override + public Verb getAccessTokenVerb() { + return Verb.POST; + } + + @Override + public String getAccessTokenEndpoint() { + return "https://open.feishu.cn/open-apis/authen/v2/oauth/token"; + } + + @Override + protected String getAuthorizationBaseUrl() { + return "https://accounts.feishu.cn/open-apis/authen/v1/authorize"; + } + + @Override + public TokenExtractor getAccessTokenExtractor() { + return OAuth2AccessTokenExtractor.instance(); + } +} diff --git a/scribejava-apis/src/main/java/com/github/scribejava/apis/LarkApi.java b/scribejava-apis/src/main/java/com/github/scribejava/apis/LarkApi.java new file mode 100644 index 000000000..63707acb9 --- /dev/null +++ b/scribejava-apis/src/main/java/com/github/scribejava/apis/LarkApi.java @@ -0,0 +1,41 @@ +package com.github.scribejava.apis; + +import com.github.scribejava.core.builder.api.DefaultApi20; +import com.github.scribejava.core.extractors.OAuth2AccessTokenExtractor; +import com.github.scribejava.core.extractors.TokenExtractor; +import com.github.scribejava.core.model.OAuth2AccessToken; +import com.github.scribejava.core.model.Verb; + +public class LarkApi extends DefaultApi20 { + + protected LarkApi() { + } + + private static class InstanceHolder { + private static final LarkApi INSTANCE = new LarkApi(); + } + + public static LarkApi instance() { + return InstanceHolder.INSTANCE; + } + + @Override + public Verb getAccessTokenVerb() { + return Verb.POST; + } + + @Override + public String getAccessTokenEndpoint() { + return "https://open.larksuite.com/open-apis/authen/v2/oauth/token"; + } + + @Override + protected String getAuthorizationBaseUrl() { + return "https://accounts.larksuite.com/open-apis/authen/v1/authorize"; + } + + @Override + public TokenExtractor getAccessTokenExtractor() { + return OAuth2AccessTokenExtractor.instance(); + } +} diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FeishuExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FeishuExample.java new file mode 100644 index 000000000..ac86a79ce --- /dev/null +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/FeishuExample.java @@ -0,0 +1,81 @@ +package com.github.scribejava.apis.examples; + +import java.util.Random; +import java.util.Scanner; +import com.github.scribejava.apis.GitHubApi; +import com.github.scribejava.core.builder.ServiceBuilder; +import com.github.scribejava.core.model.OAuth2AccessToken; +import com.github.scribejava.core.model.OAuthRequest; +import com.github.scribejava.core.model.Response; +import com.github.scribejava.core.model.Verb; +import com.github.scribejava.core.oauth.OAuth20Service; +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +public class FeishuExample { + + private static final String NETWORK_NAME = "Feishu"; + private static final String PROTECTED_RESOURCE_URL = "https://open.feishu.cn/open-apis/authen/v1/user_info"; + + private FeishuExample() { + } + + @SuppressWarnings("PMD.SystemPrintln") + public static void main(String... args) throws IOException, InterruptedException, ExecutionException { + // Replace these with your client id and secret + final String clientId = "your client id"; + final String clientSecret = "your client secret"; + final String secretState = "secret" + new Random().nextInt(999_999); + final OAuth20Service service = new ServiceBuilder(clientId) + .apiSecret(clientSecret) + .defaultScope("offline_access") // replace with desired scope + .callback("http://www.example.com/oauth_callback/") + .build(GitHubApi.instance()); + final Scanner in = new Scanner(System.in, "UTF-8"); + + System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); + System.out.println(); + + // Obtain the Authorization URL + System.out.println("Fetching the Authorization URL..."); + final String authorizationUrl = service.getAuthorizationUrl(secretState); + System.out.println("Got the Authorization URL!"); + System.out.println("Now go and authorize ScribeJava here:"); + System.out.println(authorizationUrl); + System.out.println("And paste the authorization code here"); + System.out.print(">>"); + final String code = in.nextLine(); + System.out.println(); + + System.out.println("And paste the state from server here. We have set 'secretState'='" + secretState + "'."); + System.out.print(">>"); + final String value = in.nextLine(); + if (secretState.equals(value)) { + System.out.println("State value does match!"); + } else { + System.out.println("Ooops, state value does not match!"); + System.out.println("Expected = " + secretState); + System.out.println("Got = " + value); + System.out.println(); + } + + System.out.println("Trading the Authorization Code for an Access Token..."); + final OAuth2AccessToken accessToken = service.getAccessToken(code); + System.out.println("Got the Access Token!"); + System.out.println("(The raw response looks like this: " + accessToken.getRawResponse() + "')"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + try (Response response = service.execute(request)) { + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getCode()); + System.out.println(response.getBody()); + } + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with ScribeJava! :)"); + } +} diff --git a/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LarkExample.java b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LarkExample.java new file mode 100644 index 000000000..9c99bc681 --- /dev/null +++ b/scribejava-apis/src/test/java/com/github/scribejava/apis/examples/LarkExample.java @@ -0,0 +1,81 @@ +package com.github.scribejava.apis.examples; + +import java.util.Random; +import java.util.Scanner; +import com.github.scribejava.apis.GitHubApi; +import com.github.scribejava.core.builder.ServiceBuilder; +import com.github.scribejava.core.model.OAuth2AccessToken; +import com.github.scribejava.core.model.OAuthRequest; +import com.github.scribejava.core.model.Response; +import com.github.scribejava.core.model.Verb; +import com.github.scribejava.core.oauth.OAuth20Service; +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +public class LarkExample { + + private static final String NETWORK_NAME = "Lark"; + private static final String PROTECTED_RESOURCE_URL = "https://open.larksuite.com/open-apis/authen/v1/user_info"; + + private LarkExample() { + } + + @SuppressWarnings("PMD.SystemPrintln") + public static void main(String... args) throws IOException, InterruptedException, ExecutionException { + // Replace these with your client id and secret + final String clientId = "your client id"; + final String clientSecret = "your client secret"; + final String secretState = "secret" + new Random().nextInt(999_999); + final OAuth20Service service = new ServiceBuilder(clientId) + .apiSecret(clientSecret) + .defaultScope("offline_access") // replace with desired scope + .callback("http://www.example.com/oauth_callback/") + .build(GitHubApi.instance()); + final Scanner in = new Scanner(System.in, "UTF-8"); + + System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ==="); + System.out.println(); + + // Obtain the Authorization URL + System.out.println("Fetching the Authorization URL..."); + final String authorizationUrl = service.getAuthorizationUrl(secretState); + System.out.println("Got the Authorization URL!"); + System.out.println("Now go and authorize ScribeJava here:"); + System.out.println(authorizationUrl); + System.out.println("And paste the authorization code here"); + System.out.print(">>"); + final String code = in.nextLine(); + System.out.println(); + + System.out.println("And paste the state from server here. We have set 'secretState'='" + secretState + "'."); + System.out.print(">>"); + final String value = in.nextLine(); + if (secretState.equals(value)) { + System.out.println("State value does match!"); + } else { + System.out.println("Ooops, state value does not match!"); + System.out.println("Expected = " + secretState); + System.out.println("Got = " + value); + System.out.println(); + } + + System.out.println("Trading the Authorization Code for an Access Token..."); + final OAuth2AccessToken accessToken = service.getAccessToken(code); + System.out.println("Got the Access Token!"); + System.out.println("(The raw response looks like this: " + accessToken.getRawResponse() + "')"); + System.out.println(); + + // Now let's go and ask for a protected resource! + System.out.println("Now we're going to access a protected resource..."); + final OAuthRequest request = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); + service.signRequest(accessToken, request); + try (Response response = service.execute(request)) { + System.out.println("Got it! Lets see what we found..."); + System.out.println(); + System.out.println(response.getCode()); + System.out.println(response.getBody()); + } + System.out.println(); + System.out.println("Thats it man! Go and build something awesome with ScribeJava! :)"); + } +}