使用SpringSocial开发微信登录
⒈编写微信用户对应的数据结构
package cn.coreqi.social.weixin.entities; /**
* 微信用户实体类
*/
public class WeixinUserInfo {
/**
* 普通用户的标识,对当前开发者账号唯一
*/
private String openid;
/**
* 普通用户昵称
*/
private String nickname; /**
* 语言
*/
private String language; /**
* 普通用户性别,1为男性,2为女性
*/
private String sex;
/**
* 普通用户个人资料填写的省份
*/
private String province;
/**
* 普通用户个人资料填写的城市
*/
private String city;
/**
* 国家,如中国为CN
*/
private String country;
/**
* 用户头像,最后一个数值代表正方形头像大小(有0,46,64,96,132数值可选,0代表640*640正方形)
*/
private String headimgurl;
/**
* 用户特权信息,json数组,如微信沃卡用户为(chinaunicom)
*/
private String[] privilege;
/**
* 用户统一标识,针对一个微信开放平台账号下的应用,同一用户的unionid是唯一的。
*/
private String unionid; public String getOpenid() {
return openid;
} public void setOpenid(String openid) {
this.openid = openid;
} public String getNickname() {
return nickname;
} public void setNickname(String nickname) {
this.nickname = nickname;
} public String getLanguage() {
return language;
} public void setLanguage(String language) {
this.language = language;
} public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} public String getProvince() {
return province;
} public void setProvince(String province) {
this.province = province;
} public String getCity() {
return city;
} public void setCity(String city) {
this.city = city;
} public String getCountry() {
return country;
} public void setCountry(String country) {
this.country = country;
} public String getHeadimgurl() {
return headimgurl;
} public void setHeadimgurl(String headimgurl) {
this.headimgurl = headimgurl;
} public String[] getPrivilege() {
return privilege;
} public void setPrivilege(String[] privilege) {
this.privilege = privilege;
} public String getUnionid() {
return unionid;
} public void setUnionid(String unionid) {
this.unionid = unionid;
}
}
⒉编写一个微信API接口用于获取微信用户信息
package cn.coreqi.social.weixin.api; import cn.coreqi.social.weixin.entities.WeixinUserInfo; /**
* 微信API调用接口
*/
public interface Weixin { /**
* 获取微信用户信息
* @param openId
* @return
*/
WeixinUserInfo getUserInfo(String openId);
}
⒊编写一个微信API接口实现
package cn.coreqi.social.weixin.api.impl; import cn.coreqi.social.weixin.api.Weixin;
import cn.coreqi.social.weixin.entities.WeixinUserInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.social.oauth2.AbstractOAuth2ApiBinding;
import org.springframework.social.oauth2.TokenStrategy; import java.nio.charset.Charset;
import java.util.List; /**
* 微信API调用模板,scope为Request的SpringBean,根据当前用户的accessToken创建。
*/
public class WeixinImpl extends AbstractOAuth2ApiBinding implements Weixin { /**
* 用于序列化Json数据
*/
private ObjectMapper objectMapper = new ObjectMapper(); /**
* 获取用户信息url
*/
private static final String URL_GET_USER_INFO="https://api.weixin.qq.com/sns/userinfo?openid="; /**
* WeixinImpl构造器
* @param accessToken
*/
public WeixinImpl(String accessToken){
super(accessToken, TokenStrategy.ACCESS_TOKEN_PARAMETER);
} /**
* 默认注册的HttpMessageConverter字符集为ISO-8859-1,而微信返回的是UTF-8,因此必须覆盖原来的方法
* @return
*/
@Override
protected List<HttpMessageConverter<?>> getMessageConverters() {
List<HttpMessageConverter<?>> messageConverters = super.getMessageConverters();
messageConverters.remove(0); //删除StringHttpMessageConverter
messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
return messageConverters;
} /**
* 获取微信用户信息
* @param openId
* @return
*/
@Override
public WeixinUserInfo getUserInfo(String openId) {
String url = URL_GET_USER_INFO + openId;
String response = getRestTemplate().getForObject(url,String.class);
if(StringUtils.contains(response,"errcode")){ //如果响应中存在错误码则返回null
return null;
}
WeixinUserInfo userInfo = null;
try {
userInfo = objectMapper.readValue(response,WeixinUserInfo.class);
}catch (Exception e){ }
return userInfo;
}
}
⒋编写微信access_token类
package cn.coreqi.social.weixin.connect; import org.springframework.social.oauth2.AccessGrant; /**
* 对微信access_token信息的封装
* 与标准的OAuth2协议不同,微信在获取access_token时会同时返回openId,并没有单独的通过accessToke换取openId的服务
* 在此处继承标准AccessGrant(Spring提供的令牌封装类),添加openId字段
*/
public class WeixinAccessGrant extends AccessGrant { private String openId; public WeixinAccessGrant() {
super("");
}
public WeixinAccessGrant(String accessToken, String scope, String refreshToken, Long expiresIn) {
super(accessToken, scope, refreshToken, expiresIn);
} public String getOpenId() {
return openId;
} public void setOpenId(String openId) {
this.openId = openId;
}
}
⒌编写微信OAuth2认证流程模板类。
package cn.coreqi.social.weixin.connect; import java.nio.charset.Charset;
import java.util.Map;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.social.oauth2.AccessGrant;
import org.springframework.social.oauth2.OAuth2Parameters;
import org.springframework.social.oauth2.OAuth2Template;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.databind.ObjectMapper; /**
* 完成微信的OAuth2认证流程的模板类。
* 国内厂商实现的OAuth2方式不同, Spring默认提供的OAuth2Template无法完整适配,只能针对每个厂商调整。
*/
public class WeixinOAuth2Template extends OAuth2Template { private Logger logger = LoggerFactory.getLogger(getClass()); private String clientId; private String clientSecret; private String accessTokenUrl; private static final String REFRESH_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/refresh_token"; public WeixinOAuth2Template(String clientId, String clientSecret, String authorizeUrl, String accessTokenUrl) {
super(clientId, clientSecret, authorizeUrl, accessTokenUrl);
setUseParametersForClientAuthentication(true); //请求中添加client_id和client_secret参数
this.clientId = clientId;
this.clientSecret = clientSecret;
this.accessTokenUrl = accessTokenUrl;
} /**
* 微信变更了OAuth请求参数的名称,我们覆写相应的方法按照微信的文档改为微信请求参数的名字。
* @param authorizationCode
* @param redirectUri
* @param parameters
* @return
*/
@Override
public AccessGrant exchangeForAccess(String authorizationCode, String redirectUri,
MultiValueMap<String, String> parameters) { StringBuilder accessTokenRequestUrl = new StringBuilder(accessTokenUrl); accessTokenRequestUrl.append("?appid="+clientId);
accessTokenRequestUrl.append("&secret="+clientSecret);
accessTokenRequestUrl.append("&code="+authorizationCode);
accessTokenRequestUrl.append("&grant_type=authorization_code");
accessTokenRequestUrl.append("&redirect_uri="+redirectUri); return getAccessToken(accessTokenRequestUrl);
} /**
* 微信变更了OAuth请求参数的名称,我们覆写相应的方法按照微信的文档改为微信请求参数的名字。
* @param refreshToken
* @param additionalParameters
* @return
*/
public AccessGrant refreshAccess(String refreshToken, MultiValueMap<String, String> additionalParameters) { StringBuilder refreshTokenUrl = new StringBuilder(REFRESH_TOKEN_URL); refreshTokenUrl.append("?appid="+clientId);
refreshTokenUrl.append("&grant_type=refresh_token");
refreshTokenUrl.append("&refresh_token="+refreshToken); return getAccessToken(refreshTokenUrl);
} /**
* 获取微信access_token信息
* @param accessTokenRequestUrl
* @return
*/
@SuppressWarnings("unchecked")
private AccessGrant getAccessToken(StringBuilder accessTokenRequestUrl) { logger.info("获取access_token, 请求URL: "+accessTokenRequestUrl.toString()); String response = getRestTemplate().getForObject(accessTokenRequestUrl.toString(), String.class); logger.info("获取access_token, 响应内容: "+response); Map<String, Object> result = null;
try {
result = new ObjectMapper().readValue(response, Map.class);
} catch (Exception e) {
e.printStackTrace();
} //返回错误码时直接返回空
if(StringUtils.isNotBlank(MapUtils.getString(result, "errcode"))){
String errcode = MapUtils.getString(result, "errcode");
String errmsg = MapUtils.getString(result, "errmsg");
throw new RuntimeException("获取access token失败, errcode:"+errcode+", errmsg:"+errmsg);
} WeixinAccessGrant accessToken = new WeixinAccessGrant(
MapUtils.getString(result, "access_token"),
MapUtils.getString(result, "scope"),
MapUtils.getString(result, "refresh_token"),
MapUtils.getLong(result, "expires_in")); accessToken.setOpenId(MapUtils.getString(result, "openid")); return accessToken;
} /**
* 构建获取授权码的请求。也就是引导用户跳转到微信的地址。
*/
public String buildAuthenticateUrl(OAuth2Parameters parameters) {
String url = super.buildAuthenticateUrl(parameters);
url = url + "&appid="+clientId+"&scope=snsapi_login";
return url;
} public String buildAuthorizeUrl(OAuth2Parameters parameters) {
return buildAuthenticateUrl(parameters);
} /**
* 微信返回的contentType是html/text,添加相应的HttpMessageConverter来处理。
*/
protected RestTemplate createRestTemplate() {
RestTemplate restTemplate = super.createRestTemplate();
restTemplate.getMessageConverters().add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
return restTemplate;
} }
⒍编写微信API适配器,将从微信API拿到的用户数据模型转换为Spring Social的标准用户数据模型。
package cn.coreqi.social.weixin.connect; import cn.coreqi.social.weixin.api.Weixin;
import cn.coreqi.social.weixin.entities.WeixinUserInfo;
import org.springframework.social.connect.ApiAdapter;
import org.springframework.social.connect.ConnectionValues;
import org.springframework.social.connect.UserProfile; /**
* 微信API适配器,将从微信API拿到的用户数据模型转换为Spring Social的标准用户数据模型。
* @author fanqi
*/
public class WeixinAdapter implements ApiAdapter<Weixin> { private String openId; public WeixinAdapter() {} public WeixinAdapter(String openId){
this.openId = openId;
} /**
* 用来测试当前的API是否可用
* @param api
* @return
*/
@Override
public boolean test(Weixin api) {
return true;
} /**
* 将微信的用户信息映射到ConnectionValues标准的数据化结构上
* @param api
* @param values
*/
@Override
public void setConnectionValues(Weixin api, ConnectionValues values) {
WeixinUserInfo profile = api.getUserInfo(openId);
values.setProviderUserId(profile.getOpenid());
values.setDisplayName(profile.getNickname());
values.setImageUrl(profile.getHeadimgurl());
} /**
*
* @param api
* @return
*/
@Override
public UserProfile fetchUserProfile(Weixin api) {
return null;
} /**
*
* @param api
* @param message
*/
@Override
public void updateStatus(Weixin api, String message) {
//do nothing
} }
⒎编写微信的OAuth2流程处理器的提供器
package cn.coreqi.social.weixin.connect; import cn.coreqi.social.weixin.api.Weixin;
import cn.coreqi.social.weixin.api.impl.WeixinImpl;
import org.springframework.social.oauth2.AbstractOAuth2ServiceProvider; /**
* 微信的OAuth2流程处理器的提供器,供spring social的connect体系调用
*/
public class WeixinServiceProvider extends AbstractOAuth2ServiceProvider<Weixin> { /**
* 微信获取授权码的url
*/
private static final String URL_AUTHORIZE = "https://open.weixin.qq.com/connect/qrconnect";
/**
* 微信获取accessToken的url
*/
private static final String URL_ACCESS_TOKEN = "https://api.weixin.qq.com/sns/oauth2/access_token"; /**
*
* @param appId
* @param appSecret
*/
public WeixinServiceProvider(String appId, String appSecret) {
super(new WeixinOAuth2Template(appId, appSecret,URL_AUTHORIZE,URL_ACCESS_TOKEN));
} /**
*
* @param accessToken
* @return
*/
@Override
public Weixin getApi(String accessToken) {
return new WeixinImpl(accessToken);
} }
⒏创建微信连接工厂
package cn.coreqi.social.weixin.connect; import cn.coreqi.social.weixin.api.Weixin;
import org.springframework.social.connect.ApiAdapter;
import org.springframework.social.connect.Connection;
import org.springframework.social.connect.ConnectionData;
import org.springframework.social.connect.support.OAuth2Connection;
import org.springframework.social.connect.support.OAuth2ConnectionFactory;
import org.springframework.social.oauth2.AccessGrant;
import org.springframework.social.oauth2.OAuth2ServiceProvider; /**
* 微信连接工厂
*/
public class WeixinConnectionFactory extends OAuth2ConnectionFactory<Weixin> { /**
*
* @param providerId
* @param appId
* @param appSecret
*/
public WeixinConnectionFactory(String providerId, String appId, String appSecret) {
super(providerId, new WeixinServiceProvider(appId, appSecret), new WeixinAdapter());
} /**
* 由于微信的openId是和accessToken一起返回的,所以在这里直接根据accessToken设置providerUserId即可,不用像QQ那样通过QQAdapter来获取
* @param accessGrant
* @return
*/
@Override
protected String extractProviderUserId(AccessGrant accessGrant) {
if(accessGrant instanceof WeixinAccessGrant) {
return ((WeixinAccessGrant)accessGrant).getOpenId();
}
return null;
} /**
*
* @param accessGrant
* @return
*/
public Connection<Weixin> createConnection(AccessGrant accessGrant) {
return new OAuth2Connection<Weixin>(getProviderId(), extractProviderUserId(accessGrant), accessGrant.getAccessToken(),
accessGrant.getRefreshToken(), accessGrant.getExpireTime(), getOAuth2ServiceProvider(), getApiAdapter(extractProviderUserId(accessGrant)));
} /**
*
* @param data
* @return
*/
public Connection<Weixin> createConnection(ConnectionData data) {
return new OAuth2Connection<Weixin>(data, getOAuth2ServiceProvider(), getApiAdapter(data.getProviderUserId()));
} /**
*
* @param providerUserId
* @return
*/
private ApiAdapter<Weixin> getApiAdapter(String providerUserId) {
return new WeixinAdapter(providerUserId);
} /**
*
* @return
*/
private OAuth2ServiceProvider<Weixin> getOAuth2ServiceProvider() {
return (OAuth2ServiceProvider<Weixin>) getServiceProvider();
} }
⒐创建微信登陆配置类
package cn.coreqi.social.weixin.config; import cn.coreqi.social.weixin.connect.WeixinConnectionFactory;
import org.springframework.boot.autoconfigure.social.SocialAutoConfigurerAdapter;
import org.springframework.context.annotation.Configuration;
import org.springframework.social.connect.ConnectionFactory; /**
* 微信登录配置
*/
@Configuration
public class WeixinAutoConfiguration extends SocialAutoConfigurerAdapter { @Override
protected ConnectionFactory<?> createConnectionFactory() {
String providerId = "weixin"; //第三方id,用来决定发起第三方登录的url,默认是weixin
String appId = "";
String appSecret = "";
return new WeixinConnectionFactory(providerId, appId,
appSecret);
} }
使用SpringSocial开发微信登录的更多相关文章
- Spring Security构建Rest服务-1000-使用SpringSocial开发第三方登录之大白话OAuth协议
OAuth协议简介 OAuth协议要解决的问题 OAuth协议中的各种角色 OAuth协议运行流程 OAuth协议,在网上也看了一些资料,意思就是给你颁发一个临时的通行证,你拿着这个通行证可以访 ...
- 使用SpringSocial开发QQ登录
⒈编写QQ用户对应的数据结构 package cn.coreqi.social.qq.entities; /** * 封装QQ的用户信息 */ public class QQUserInfo { /* ...
- 微信开放平台--》网站应用开发 微信登录网站接口(https://open.weixin.qq.com/)
地址:https://open.weixin.qq.com/ 手册:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&am ...
- 网站实现微信登录之回调函数中登录逻辑的处理--基于yii2开发的描述
上一篇文章网站实现微信登录之嵌入二维码中描述了如何在自己的登录页面内嵌入登录二维码,今天的这篇文章主要是描述下在扫码成功之后微信重定向回网站后登录逻辑的处理,其实也就是验证身份信息,授权用户登录的逻辑 ...
- 网站实现微信登录之嵌入二维码——基于yii2开发的描述
之前写了一篇yii2获取登录前的页面url地址的文章,然后发现自己对于网站实现微信扫码登录功能的实现不是很熟悉,所以,我会写2-3篇的文章来描述下一个站点如何实现微信扫码登录的功能,来复习下微信扫码登 ...
- C#开发微信门户及应用(45)--微信扫码登录
在前面随笔<C#开发微信门户及应用(41)--基于微信开放平台的扫码登录处理>介绍了基于微信开放平台接口实现的微信扫码直接登录的过程.本篇介绍对扫码登录的一些改进和处理,以便更方便应用在实 ...
- PHP开发网站之微信登录、绑定
)))刷新access_token()); ); ); curl_setopt($curlobj, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($curlo ...
- 用c#开发微信 (20) 微信登录网站 - 扫描二维码登录
像京东,一号店等网站都实现了用微信来登录的功能,就是用手机上的微信扫一扫网站上的二维码,微信上确认后,即可自动用微信的帐号登录网站. 1 创建网站应用 在微信开放平台创建一个网站应用 https:// ...
- iOS开发笔记14:微博/微信登录与分享、微信/支付宝支付
产品中接入了微博/微信的第三方登录分享功能.微信和支付宝的第三方支付功能,之前在开发过程中涉及到这些部分,于是抽空将接入过程梳理了一遍. 1.微博.微信.支付宝SDK相关接入设置 (1)微博SDK S ...
随机推荐
- CactiEZ中文解决方案和使用教程
CactiEZ中文版是最简单有效的Cacti中文解决方案,整合Spine,RRDTool和美化字体.集成Thold,Monitor,Syslog,Weathermap,Realtime,Errorim ...
- 如何在Mac上安全彻底的卸载软件?
文章来源:知乎 收录于:风云社区(SCOEE)[提供mac软件下载] 更多专题,可关注小编[磨人的小妖精],查看我的文章,也可上[风云社区 SCOEE],查找和下载相关软件资源. (一)综合类: 新买 ...
- mysql主从模式下在主库上的某些操作不记录日志的方法
mysql主从模式下在主库上的某些操作不记录日志的方法 需求场景: 在主库上的需要删除某个用户,而这个用户在从库上不存在(我在接手一个业务的时候,就遇到主从架构用户授权不一致的情况,主库比较全,而从库 ...
- 3D转换(位置)+过渡+透视
效果如图: html代码: <div class="door"> <div class="in"><div> </di ...
- JAVA-序列化深拷贝对象
序列化拷贝方法 @SuppressWarnings("unchecked") public static <T extends Serializable> T clon ...
- Linux记录-HDFS副本机制
1. 副本策略 NameNode具有RackAware机架感知功能,这个可以配置. 若client为DataNode节点,那存储block时,规则为:副本1,同client的节点上:副本2,不同机架节 ...
- React 记录(1)
作为一个前端工程师,前端框架是必须会的,所以开始学习React. 学习的方法是:先实践,后图文记录. React官网:https://reactjs.org React中文网站:https://www ...
- 【leetcode70】【动态规划】 爬楼梯
(1 pass 一维动态规划) 爬楼梯(easy) 假设你正在爬楼梯.需要 n 阶你才能到达楼顶. 每次你可以爬 1 或 2 个台阶.你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数 ...
- ArcGIS坐标系转换出错:Error 999999执行函数出错 invalid extent for output coordinate system
本文主要介绍在用ArcGIS做坐标系转换过程中可能会遇到的一个问题,并分析其原因和解决方案. 如下图,对一份数据做坐标系转换: 过了一会儿,转换失败了.错误消息如下: “消息”中提示,“执行函数出错 ...
- Mac 开发使用中的小技巧收集
1. mac 下ssh连接到 linux 服务器管理,同putty,无需第三方 Mac 下打开终端,输入: ssh 登录用户名@ip地址 如: ssh root@142.138.1.89 如有询问是否 ...