您的位置:首页 > 编程语言 > Java开发

基于Spring的微信第三方登录实现

2016-02-29 12:26 507 查看
在前几篇文章中,我们介绍了OAuth2.0认证和授权机制讲解,并实现了基于Spring的Github第三方登录--通用化的第三方登陆实现,之后,我们基于该通用化的框架,介绍了国内的两个比较流行的第三方登录平台:基于Spring的新浪微博第三方登录实现基于Spring的QQ第三方登录实现。以上几个第三方登录平台都严格遵守了OAuth2.0协议。但是,近来作者发现微信的第三方登录确不是那么严格的遵守通用化的OAuth2.0协议,有些细节实现不太一样(例如获取AccessToken时其他OAuth平台用的字段名为client_id,但是微信中是appid),这就导致了之前的通用化框架在微信登录时遇到了很多问题,今天我们就来介绍一下微信的第三方登录,并重构一下我们的通用化框架,使之在遇到其他不那么严格遵守OAuth协议的平台依然简单实用。


申请第三方应用

接下来我们首先来看看如何在微信开放平台中申请一个第三方应用。

首先,我们需要完善开发者资质认证,在导航栏选择【账号中心】,然后选择【开发者资质认证】,我们会看到如下页面:





从页面信息介绍中的第二点我们可以知道,通过开发者资质认证后,我们就能够获得微信第三方登录的能力。需要注意:个人是不能申请第三方认证的,必须为以下机构或者团体才能进行认证,每次审核需要花费300元:





开发者资质认证提交并缴费后,会在两个工作日内进行审核,如果有问题会有客服人员电话沟通。

审核完成后,进入【管理中心】-> 【网站应用】。





点击【创建网站应用】,按照其提示填写相关内容即可:









提交完成后,如果你的开发者资质已经通过,就可以直接进行开发上线啦。现在,让我们看看如何添加微信第三方登录的代码。


第三方登录通用架构

现在,我们将基于Spring的Github第三方登录--通用化的第三方登陆实现中的通用化架构添加到代码中来,以此为基础添加微信登录的相关功能:





微信第三方登录服务分析

首先,让我们我们看看微信登录开发文档,看过之后,我们发现微信登录虽然是基于OAuth2.0协议,但是API的参数确不一样。之前我们做过github、微博、QQ其获取Access
Token时所需的参数为
client_id
以及
client_secret
,Scribe默认的OAuthService在处理也是同样的参数,因此我们可以通过其默认的
OAuth20ServiceImpl
来处理OAuth的相关操作。

但是微信中
client_id
client_secret
两个参数统一用的是:
appid
secret
。这也就意味着我们需要实现自己的
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端口,运行时需要超级管理员权限。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: