1. 程式人生 > >基於Spring的微信第三方登入實現

基於Spring的微信第三方登入實現

在前幾篇文章中,我們介紹了OAuth2.0認證和授權機制講解,並實現了基於Spring的Github第三方登入--通用化的第三方登陸實現,之後,我們基於該通用化的框架,介紹了國內的兩個比較流行的第三方登入平臺:基於Spring的新浪微博第三方登入實現基於Spring的QQ第三方登入實現。以上幾個第三方登入平臺都嚴格遵守了OAuth2.0協議。但是,近來作者發現微信的第三方登入確不是那麼嚴格的遵守通用化的OAuth2.0協議,有些細節實現不太一樣(例如獲取AccessToken時其他OAuth平臺用的欄位名為client_id,但是微信中是appid),這就導致了之前的通用化框架在微信登入時遇到了很多問題,今天我們就來介紹一下微信的第三方登入,並重構一下我們的通用化框架,使之在遇到其他不那麼嚴格遵守OAuth協議的平臺依然簡單實用。

申請第三方應用

接下來我們首先來看看如何在微信開放平臺中申請一個第三方應用。

首先,我們需要完善開發者資質認證,在導航欄選擇【賬號中心】,然後選擇【開發者資質認證】,我們會看到如下頁面:

alter-text

從頁面資訊介紹中的第二點我們可以知道,通過開發者資質認證後,我們就能夠獲得微信第三方登入的能力。需要注意:個人是不能申請第三方認證的,必須為以下機構或者團體才能進行認證,每次稽核需要花費300元:

alter-text

開發者資質認證提交併繳費後,會在兩個工作日內進行稽核,如果有問題會有客服人員電話溝通。

稽核完成後,進入【管理中心】-> 【網站應用】。

alter-text

點選【建立網站應用】,按照其提示填寫相關內容即可:

alter-text

alter-text

提交完成後,如果你的開發者資質已經通過,就可以直接進行開發上線啦。現在,讓我們看看如何新增微信第三方登入的程式碼。

第三方登入通用架構

alter-text

微信第三方登入服務分析

首先,讓我們我們看看微信登入開發文件,看過之後,我們發現微信登入雖然是基於OAuth2.0協議,但是API的引數確不一樣。之前我們做過github、微博、QQ其獲取Access Token時所需的引數為client_id以及client_secret,Scribe預設的OAuthService在處理也是同樣的引數,因此我們可以通過其預設的OAuth20ServiceImpl來處理OAuth的相關操作。

但是微信中client_idclient_secret兩個引數統一用的是:appidsecret。這也就意味著我們需要實現自己的WeixinOAuth20Service

來對這些細節進行處理。同時,新增完成後,我們還需要新增一個WeixinOAuthDeractorService來適配通用化的第三方登陸實現中的設計。

但是WeixinOAuth20Service以及WeixinOAuthDeractorService實際上功能是一樣的,只是我們需要一個CustomOAuthService來對OAuthService進行管理。如果我們通過一個介面對OAuthService進行管理的話,我們就只需要新增一個類WeixinOAuthService即可,同時這也符合依賴於介面而不是實現的最佳原則。

通過介面管理OAuthService

我們首先來新增一個介面CustomOAuthService:

public interface CustomOAuthService extends OAuthService{

    String getoAuthType();
    String getAuthorizationUrl();
    OAuthUser getOAuthUser(Token accessToken);

}

之後,我們將之前所有對OAuthServiceDeractor修改為CustomOAuthService

@Service
public class OAuthServices {

    @Autowired List<CustomOAuthService> oAuthServiceDeractors;

    public CustomOAuthService getOAuthService(String type){
        Optional<CustomOAuthService> oAuthService = oAuthServiceDeractors.stream().filter(o -> o.getoAuthType().equals(type))
                .findFirst();
        if(oAuthService.isPresent()){
            return oAuthService.get();
        }
        return null;
    }

    public List<CustomOAuthService> getAllOAuthServices(){
        return oAuthServiceDeractors;
    }

}

這樣,我們對於第三方框架的重構就完成了。接下來我們來具體實現微信的第三方登入。

WeixinApi

首先,新增WeixinApi,為OAuthService提供進行OAuth驗證的各個地址,相關的地址可以在微信登入開發文件中得到,想了解微信第三方登入具體細節的同學可以仔細研讀一下該文件。最終的WeixinApi程式碼如下:

public class WeixinApi extends DefaultApi20 {

    private static final String AUTHORIZE_URL = "https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&state=esfadsgsad34fwdef&scope=snsapi_login#wechat_redirect";
    private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?grant_type=authorization_code";

    @Override
    public String getAuthorizationUrl(OAuthConfig config) {
        return String.format(AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback()));
    }

    @Override
    public String getAccessTokenEndpoint() {
        return ACCESS_TOKEN_URL;
    }

    @Override
    public OAuthService createService(OAuthConfig config){
      return new WeixinOAuthService(this, config);
    }
}

WeixinOAuthService

最後是WeixinOAuthService的實現,除了CustomOAuthService的所定位的方法外,我們還需要重寫getAccessToken

public class WeixinOAuthService extends OAuth20ServiceImpl implements CustomOAuthService {

    private final DefaultApi20 api;
    private final OAuthConfig config;
    private final String authorizationUrl;

    public WeixinOAuthService(DefaultApi20 api, OAuthConfig config) {
        super(api, config);
        this.api = api;
        this.config = config;
        this.authorizationUrl = getAuthorizationUrl(null);
    }

    @Override
    public Token getAccessToken(Token requestToken, Verifier verifier){
      OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint());
      request.addQuerystringParameter("appid", config.getApiKey());
      request.addQuerystringParameter("secret", config.getApiSecret());
      request.addQuerystringParameter(OAuthConstants.CODE, verifier.getValue());
      if(config.hasScope()) request.addQuerystringParameter(OAuthConstants.SCOPE, config.getScope());
      Response response = request.send();
      String responceBody = response.getBody();
      Object result = JSON.parse(responceBody);
      return new Token(JSONPath.eval(result, "$.access_token").toString(), "", responceBody);
    }

    @Override
    public OAuthUser getOAuthUser(Token accessToken) {
        OAuthUser oAuthUser = new OAuthUser();
        oAuthUser.setoAuthType(getoAuthType());
        Object result = JSON.parse(accessToken.getRawResponse());
        oAuthUser.setoAuthId(JSONPath.eval(result, "$.openid").toString());
        oAuthUser.setUser(new User());
        return oAuthUser;
    }

    @Override
    public String getoAuthType() {
        return OAuthTypes.WEIXIN;
    }

    @Override
    public String getAuthorizationUrl() {
        return authorizationUrl;
    }

}

配置WeixinOAuthService

最後新增WeixinOAuthService的相關配置:

@Configuration
public class OAuthConfig {

    private static final String CALLBACK_URL = "http://tianmaying.com/oauth/%s/callback";

    @Value("${oAuth.weixin.appId}") String weixinAppId;
    @Value("${oAuth.weixin.appSecret}") String weixinAppSecret;

    @Bean
    public CustomOAuthService getSinaOAuthService(){
        return (CustomOAuthService) new ServiceBuilder()
            .provider(WeixinApi.class)
            .apiKey(weixinAppId)
            .apiSecret(weixinAppSecret)
            .scope("snsapi_login")
            .callback(String.format(CALLBACK_URL, OAuthTypes.WEIXIN))
            .build();
    }


}

修改hosts

與新浪微博一樣,修改hosts一遍進行本地除錯。

windows系統hosts檔案一般在C:\WINDOWS\system32\drivers\etc

mac系統hosts檔案地址一般為:/etc/hosts

在hosts檔案新增以下一行:

127.0.0.1       tianmaying.com

除錯

進入根目錄,執行sudo mvn spring-boot:run命令,訪問http://tianmaying.com (之前填寫應用資訊以及修改hosts時所填寫的域名,這三個域名必須一致),由於必須通過域名進行訪問,所以我們需要監聽80埠,執行時需要超級管理員許可權。


進一步閱讀

版權宣告 本文由