-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Add WeChat API #739
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add WeChat API #739
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| package com.github.scribejava.apis; | ||
|
|
||
| import com.github.scribejava.apis.service.WeChatOAuth20ServiceImpl; | ||
| import com.github.scribejava.apis.wechat.WeChatConstants; | ||
| import com.github.scribejava.apis.wechat.WeChatJsonTokenExtractor; | ||
| import com.github.scribejava.core.builder.api.DefaultApi20; | ||
| import com.github.scribejava.core.builder.api.SignatureType; | ||
| import com.github.scribejava.core.extractors.TokenExtractor; | ||
| import com.github.scribejava.core.model.OAuth2AccessToken; | ||
| import com.github.scribejava.core.model.OAuthConfig; | ||
| import com.github.scribejava.core.model.ParameterList; | ||
| import com.github.scribejava.core.oauth.OAuth20Service; | ||
|
|
||
| import java.util.Map; | ||
|
|
||
| /** | ||
| * WeChat OAuth 2.0 api. | ||
| */ | ||
| public class WeChatApi20 extends DefaultApi20 { | ||
|
|
||
| protected WeChatApi20() { | ||
| } | ||
|
|
||
| private static class InstanceHolder { | ||
| private static final WeChatApi20 INSTANCE = new WeChatApi20(); | ||
| } | ||
|
|
||
| public static WeChatApi20 instance() { | ||
| return InstanceHolder.INSTANCE; | ||
| } | ||
|
|
||
| @Override | ||
| public String getAccessTokenEndpoint() { | ||
| return "https://api.weixin.qq.com/sns/oauth2/access_token"; | ||
| } | ||
|
|
||
| @Override | ||
| protected String getAuthorizationBaseUrl() { | ||
| return "https://open.weixin.qq.com/connect/qrconnect"; | ||
| } | ||
|
|
||
| @Override | ||
| public String getAuthorizationUrl(OAuthConfig config, Map<String, String> additionalParams) { | ||
|
|
||
| final ParameterList parameters = new ParameterList(additionalParams); | ||
| parameters.add(WeChatConstants.RESPONSE_TYPE, config.getResponseType()); | ||
| parameters.add(WeChatConstants.CLIENT_ID, config.getApiKey()); | ||
|
|
||
| final String callback = config.getCallback(); | ||
| if (callback != null) { | ||
| parameters.add(WeChatConstants.REDIRECT_URI, callback); | ||
| } | ||
|
|
||
| final String scope = config.getScope(); | ||
| if (scope != null) { | ||
| parameters.add(WeChatConstants.SCOPE, scope); | ||
| } | ||
|
|
||
| final String state = config.getState(); | ||
| if (state != null) { | ||
| parameters.add(WeChatConstants.STATE, state); | ||
| } | ||
|
|
||
| return parameters.appendTo(getAuthorizationBaseUrl()); | ||
| } | ||
|
|
||
| @Override | ||
| public OAuth20Service createService(OAuthConfig config) { | ||
| return new WeChatOAuth20ServiceImpl(this, config); | ||
| } | ||
|
|
||
| @Override | ||
| public SignatureType getSignatureType() { | ||
| return SignatureType.BEARER_URI_QUERY_PARAMETER; | ||
| } | ||
|
|
||
| @Override | ||
| public TokenExtractor<OAuth2AccessToken> getAccessTokenExtractor() { | ||
| return WeChatJsonTokenExtractor.instance(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| package com.github.scribejava.apis.service; | ||
|
|
||
| import com.github.scribejava.apis.wechat.WeChatConstants; | ||
| import com.github.scribejava.core.builder.api.DefaultApi20; | ||
| import com.github.scribejava.core.model.OAuthConfig; | ||
| import com.github.scribejava.core.model.OAuthRequest; | ||
| import com.github.scribejava.core.oauth.OAuth20Service; | ||
|
|
||
| public class WeChatOAuth20ServiceImpl extends OAuth20Service { | ||
|
|
||
| public WeChatOAuth20ServiceImpl(DefaultApi20 api, OAuthConfig config) { | ||
| super(api, config); | ||
| } | ||
|
|
||
| @Override | ||
| protected OAuthRequest createAccessTokenRequest(String code) { | ||
|
|
||
| final DefaultApi20 api = getApi(); | ||
| final OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint()); | ||
| final OAuthConfig config = getConfig(); | ||
|
|
||
| request.addParameter(WeChatConstants.CLIENT_ID, config.getApiKey()); | ||
| request.addParameter(WeChatConstants.CLIENT_SECRET, config.getApiSecret()); | ||
| request.addParameter(WeChatConstants.CODE, code); | ||
| request.addParameter(WeChatConstants.GRANT_TYPE, WeChatConstants.AUTHORIZATION_CODE); | ||
|
|
||
| return request; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the same here. |
||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package com.github.scribejava.apis.wechat; | ||
|
|
||
| import com.github.scribejava.core.model.OAuthConstants; | ||
|
|
||
| /** | ||
| * This class contains OAuth constants, Custom for WeChat. | ||
| */ | ||
| public interface WeChatConstants extends OAuthConstants { | ||
|
|
||
| // WeChat's client_id is called appid and client_secret is called secret | ||
| String CLIENT_ID = "appid"; | ||
| String CLIENT_SECRET = "secret"; | ||
|
|
||
| String LANG = "lang"; | ||
| String OPEN_ID = "openid"; | ||
| String UNION_ID = "unionid"; | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| package com.github.scribejava.apis.wechat; | ||
|
|
||
| import com.github.scribejava.core.extractors.OAuth2AccessTokenJsonExtractor; | ||
|
|
||
| import java.util.regex.Pattern; | ||
|
|
||
| /** | ||
| * additionally parses openId openid and unionId unionid. | ||
| */ | ||
| public class WeChatJsonTokenExtractor extends OAuth2AccessTokenJsonExtractor { | ||
|
|
||
| private static final Pattern OPEN_ID_REGEX_PATTERN = Pattern.compile("\"openid\"\\s*:\\s*\"(\\S*?)\""); | ||
| private static final Pattern UNION_ID_REGEX_PATTERN = Pattern.compile("\"unionid\"\\s*:\\s*\"(\\S*?)\""); | ||
|
|
||
| protected WeChatJsonTokenExtractor() { | ||
| } | ||
|
|
||
| private static class InstanceHolder { | ||
|
|
||
| private static final WeChatJsonTokenExtractor INSTANCE = new WeChatJsonTokenExtractor(); | ||
| } | ||
|
|
||
| public static WeChatJsonTokenExtractor instance() { | ||
| return WeChatJsonTokenExtractor.InstanceHolder.INSTANCE; | ||
| } | ||
|
|
||
| @Override | ||
| protected WeChatToken createToken(String accessToken, String tokenType, Integer expiresIn, | ||
| String refreshToken, String scope, String response) { | ||
| return new WeChatToken(accessToken, tokenType, expiresIn, refreshToken, scope, | ||
| extractParameter(response, OPEN_ID_REGEX_PATTERN, false), | ||
| extractParameter(response, UNION_ID_REGEX_PATTERN, false), response); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| package com.github.scribejava.apis.wechat; | ||
|
|
||
| import com.github.scribejava.core.model.OAuth2AccessToken; | ||
|
|
||
| import java.util.Objects; | ||
|
|
||
| public class WeChatToken extends OAuth2AccessToken { | ||
|
|
||
| // Unique identifier for Authorized user | ||
| private final String openId; | ||
|
|
||
| // User's unified identifier for a WeChat open platform account | ||
| private final String unionId; | ||
|
|
||
| public WeChatToken(String accessToken, String openId, String unionId, String rawResponse) { | ||
| this(accessToken, null, null, null, null, openId, unionId, rawResponse); | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems we don't need this constructor. Constructor in GoogleToken as well. |
||
|
|
||
| public WeChatToken(String accessToken, String tokenType, Integer expiresIn, String refreshToken, String scope, | ||
| String openId, String unionId, String rawResponse) { | ||
| super(accessToken, tokenType, expiresIn, refreshToken, scope, rawResponse); | ||
| this.openId = openId; | ||
| this.unionId = unionId; | ||
|
|
||
| } | ||
|
|
||
| public String getOpenId() { | ||
| return openId; | ||
| } | ||
|
|
||
| public String getUnionId() { | ||
| return unionId; | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| int hash = super.hashCode(); | ||
| hash = 37 * hash + Objects.hashCode(openId); | ||
| hash = 37 * hash + Objects.hashCode(unionId); | ||
| return hash; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object obj) { | ||
| if (this == obj) { | ||
| return true; | ||
| } | ||
| if (obj == null) { | ||
| return false; | ||
| } | ||
| if (getClass() != obj.getClass()) { | ||
| return false; | ||
| } | ||
| if (!super.equals(obj)) { | ||
| return false; | ||
| } | ||
| if (!Objects.equals(openId, ((WeChatToken) obj).getOpenId())) { | ||
| return false; | ||
| } | ||
| return Objects.equals(unionId, ((WeChatToken) obj).getUnionId()); | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "WeChatToken{" | ||
| + "access_token=" + getAccessToken() | ||
| + ", expires_in=" + getExpiresIn() | ||
| + ", refresh_token=" + getRefreshToken() | ||
| + ", openid=" + openId | ||
| + ", scope=" + getScope() | ||
| + ", unionid=" + unionId | ||
| + '}'; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| package com.github.scribejava.apis.examples; | ||
|
|
||
| import com.github.scribejava.apis.WeChatApi20; | ||
| import com.github.scribejava.apis.wechat.WeChatConstants; | ||
| import com.github.scribejava.apis.wechat.WeChatToken; | ||
| 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.Scanner; | ||
| import java.util.concurrent.ExecutionException; | ||
|
|
||
| public final class WeChat20Example { | ||
|
|
||
| private static final String NETWORK_NAME = "WeChat"; | ||
| private static final String PROTECTED_RESOURCE_URL = "https://api.weixin.qq.com/sns/userinfo"; | ||
|
|
||
| private WeChat20Example() { | ||
| } | ||
|
|
||
| public static void main(String... args) throws IOException, InterruptedException, ExecutionException { | ||
| // Replace these with your own api key and secret | ||
| final String apiKey = "your_appid"; | ||
| final String apiSecret = "your_secret"; | ||
| final OAuth20Service service = new ServiceBuilder() | ||
| .apiKey(apiKey) | ||
| .apiSecret(apiSecret) | ||
| .callback("http://your.site.com/callback") // your application's authorized callback field | ||
| .scope("snsapi_login") | ||
| .state("login") | ||
| .build(WeChatApi20.instance()); | ||
| final Scanner in = new Scanner(System.in); | ||
|
|
||
| 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(); | ||
| 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(); | ||
|
|
||
| // Trade the Request Token and Verifier for the Access Token | ||
| System.out.println("Trading the Request Token for an Access Token..."); | ||
| final OAuth2AccessToken accessToken = service.getAccessToken(code); | ||
| System.out.println("Got the Access Token!"); | ||
| System.out.println("(if your curious it looks like this: " + accessToken | ||
| + ", 'rawResponse'='" + 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); | ||
| request.addQuerystringParameter(WeChatConstants.OPEN_ID, ((WeChatToken) accessToken).getOpenId()); | ||
| request.addQuerystringParameter(WeChatConstants.LANG, "zh_CN"); | ||
|
|
||
| service.signRequest(accessToken, request); | ||
| final 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! :)"); | ||
|
|
||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pity. for single param name...
Maybe let it be like this:
or even