1. 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据code参数;
2. 通过code参数加上AppID和AppSecret等,通过API换取access_token;
3. 通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。
获取access_token时序图:
微信网站应用授权登录接口对接代码实现:
需用的配置文件:
需用的vo类:
代码:
mon.vo;
/**
*类名:WechatAccessTokenVo*描述:授权关系接口的调用凭证模型*开发人员:weining*创建时间:/5/5*/
publicclassWechatAccessTokenVo{
//网页授权接口调用凭证
privateStringaccessToken;
//凭证有效时长
privateintexpiresIn;
//用于刷新凭证
privateStringrefreshToken;
//用户标识
privateStringopenId;
//用户授权作用域
privateStringscope;
//用户全局唯一标识unionid
privateStringunionid;
publicStringgetAccessToken(){
returnaccessToken;
}
publicvoidsetAccessToken(StringaccessToken){
this.accessToken=accessToken;
}
publicintgetExpiresIn(){
returnexpiresIn;
}
publicvoidsetExpiresIn(intexpiresIn){
this.expiresIn=expiresIn;
}
publicStringgetRefreshToken(){
returnrefreshToken;
}
publicvoidsetRefreshToken(StringrefreshToken){
this.refreshToken=refreshToken;
}
publicStringgetOpenId(){
returnopenId;
}
publicvoidsetOpenId(StringopenId){
this.openId=openId;
}
publicStringgetScope(){
returnscope;
}
publicvoidsetScope(Stringscope){
this.scope=scope;
}
publicStringgetUnionid(){
returnunionid;
}
publicvoidsetUnionid(Stringunionid){
this.unionid=unionid;
}
}
mon.vo;
importjava.util.List;
/**
*类名:WechatSNSUserInfoVo*描述:通过网页授权获取的用户信息*开发人员:weining*创建时间:/4/27*/
publicclassWechatSNSUserInfoVo{
//用户标识
privateStringopenId;
//用户昵称
privateStringnickname;
//性别(1是男性,2是女性,0是未知)
privateintsex;
//国家
privateStringcountry;
//省份
privateStringprovince;
//城市
privateStringcity;
//用户头像链接
privateStringheadImgUrl;
//用户特权信息
privateListprivilegeList;
//用户全局唯一标识unionid
privateStringunionid;
publicStringgetOpenId(){
returnopenId;
}
publicvoidsetOpenId(StringopenId){
this.openId=openId;
}
publicStringgetNickname(){
returnnickname;
}
publicvoidsetNickname(Stringnickname){
this.nickname=nickname;
}
publicintgetSex(){
returnsex;
}
publicvoidsetSex(intsex){
this.sex=sex;
}
publicStringgetCountry(){
returncountry;
}
publicvoidsetCountry(Stringcountry){
this.country=country;
}
publicStringgetProvince(){
returnprovince;
}
publicvoidsetProvince(Stringprovince){
this.province=province;
}
publicStringgetCity(){
returncity;
}
publicvoidsetCity(Stringcity){
this.city=city;
}
publicStringgetHeadImgUrl(){
returnheadImgUrl;
}
publicvoidsetHeadImgUrl(StringheadImgUrl){
this.headImgUrl=headImgUrl;
}
publicListgetPrivilegeList(){
returnprivilegeList;
}
publicvoidsetPrivilegeList(ListprivilegeList){
this.privilegeList=privilegeList;
}
publicStringgetUnionid(){
returnunionid;
}
publicvoidsetUnionid(Stringunionid){
this.unionid=unionid;
}
}
需要的工具类:
代码 :
mon.utils.wechat;
importcom.alibaba.fastjson.JSONObject;
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
.ssl.HttpsURLConnection;
.ssl.SSLContext;
.ssl.SSLSocketFactory;
.ssl.TrustManager;
importjava.io.BufferedReader;
importjava.io.InputStream;
importjava.io.InputStreamReader;
importjava.io.OutputStream;
.ConnectException;
.URL;
/**
*类名:WechatCommonUtil*描述:微信登录通用工具类*开发人员:weining*创建时间:/5/5*/
publicclassWechatCommonUtil{
privatestaticLoggerlog=LoggerFactory.getLogger(WechatCommonUtil.class);
/**
*发送https请求
*
*@paramrequestUrl请求地址
*@paramrequestMethod请求方式(GET、POST)
*@paramoutputStr提交的数据
*@returnJSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
*/
publicstaticJSONObjecthttpsRequest(StringrequestUrl,StringrequestMethod,StringoutputStr){
JSONObjectjsonObject=null;
try{
//创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[]tm={newWechatX509TrustManager()};
SSLContextsslContext=SSLContext.getInstance("SSL","SunJSSE");
sslContext.init(null,tm,newjava.security.SecureRandom());
//从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactoryssf=sslContext.getSocketFactory();
URLurl=newURL(requestUrl);
HttpsURLConnectionconn=(HttpsURLConnection)url.openConnection();
conn.setSSLSocketFactory(ssf);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
//设置请求方式(GET/POST)
conn.setRequestMethod(requestMethod);
//当outputStr不为null时向输出流写数据
if(null!=outputStr){
OutputStreamoutputStream=conn.getOutputStream();
//注意编码格式
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
//从输入流读取返回内容
InputStreaminputStream=conn.getInputStream();
InputStreamReaderinputStreamReader=newInputStreamReader(inputStream,"utf-8");
BufferedReaderbufferedReader=newBufferedReader(inputStreamReader);
Stringstr=null;
StringBufferbuffer=newStringBuffer();
while((str=bufferedReader.readLine())!=null){
buffer.append(str);
}
//释放资源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream=null;
conn.disconnect();
jsonObject=JSONObject.parseObject(buffer.toString());
}catch(ConnectExceptionce){
log.error("连接超时:{}",ce);
}catch(Exceptione){
log.error("https请求异常:{}",e);
}
returnjsonObject;
}
}
mon.utils.wechat;
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
importjava.io.IOException;
importjava.io.InputStream;
importjava.util.Properties;
/**
*类名:WechatConfigLoader*描述:微信初始化配置信息*开发人员:weining*创建时间:/5/5*/
publicclassWechatConfigLoader{
//日志记录对象
privatestaticLoggerlog=LoggerFactory.getLogger(WechatConfigLoader.class);
//配置文件路径
privatestaticStringwechatPath="wechat.properties";
//开发平台应用唯一标识
privatestaticStringappId;
//开放平台应用密钥
privatestaticStringappSecret;
//微信第三方回调地址
privatestaticStringbackUrl;
static{
//类初始化后加载配置文件
InputStreamin=WechatConfigLoader.class.getClassLoader()
.getResourceAsStream(wechatPath);
Propertiesprops=newProperties();
try{
props.load(in);
}catch(IOExceptione){
log.error("loadwechatsettingerror,pleacecheckthefilepath:"
+wechatPath);
log.error(e.toString(),e);
}
appId=props.getProperty("wechat.appId");
appSecret=props.getProperty("wechat.appSecret");
backUrl=props.getProperty("wechat.backUrl");
log.debug("loadwechatsettingsuccess,filepath:"+wechatPath);
}
publicstaticStringgetAppId(){
returnappId;
}
publicstaticStringgetAppSecret(){
returnappSecret;
}
publicstaticStringgetBackUrl(){
returnbackUrl;
}
publicstaticvoidsetWechatPath(StringwechatPath){
WechatConfigLoader.wechatPath=wechatPath;
}
publicstaticStringgetWechatPath(){
returnwechatPath;
}
publicstaticvoidsetAppId(StringappId){
WechatConfigLoader.appId=appId;
}
publicstaticvoidsetAppSecret(StringappSecret){
WechatConfigLoader.appSecret=appSecret;
}
publicstaticvoidsetBackUrl(StringbackUrl){
WechatConfigLoader.backUrl=backUrl;
}
}
packagecom.mon.wechatUtil;
importcom.alibaba.fastjson.JSONArray;
importcom.alibaba.fastjson.JSONObject;
importcom.mon.wechatVo.WechatAccessTokenVo;
importcom.mon.wechatVo.WechatSNSUserInfoVo;
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importjava.io.IOException;
.URLEncoder;
importjava.util.List;
/**
*类名:WXOAuthProcess*描述:微信第三方登录授权流程工具类*开发人员:weining*创建时间:/5/5*/
publicclassWechatOAuthProcessUtil{
privatestaticLoggerlog=LoggerFactory.getLogger(WechatOAuthProcessUtil.class);
/**
*1.获取授权code
*@paramreq
*@paramresp
*/
publicstaticvoidgetOAuthCode(HttpServletRequestreq,HttpServletResponseresp){
StringappId=WechatConfigLoader.getAppId();
StringbackUrl=WechatConfigLoader.getBackUrl();
Stringurl="https://open./connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_login&state=STATE#wechat_redirect";
url=url.replace("APPID",appId);
url=url.replace("REDIRECT_URI",URLEncoder.encode(backUrl));
try{
resp.sendRedirect(url);
}catch(IOExceptione){
e.printStackTrace();
}
}
/**
*2.获取授权调用token
*@paramappId开发平台应用唯一标识
*@paramappSecret开放平台应用密钥
*@paramcode授权临时票据根据code来换取accessToken
*/
publicstaticWechatAccessTokenVogetOauthAccessToken(StringappId,StringappSecret,Stringcode){
WechatAccessTokenVowechatAccessTokenVo=null;
//拼接微信获取accessToken请求的链接
Stringurl="https://api./sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
url=url.replace("APPID",appId);
url=url.replace("SECRET",appSecret);
url=url.replace("CODE",code);
//获取网页授权凭证发送https请求
JSONObjectjsonObject=(WechatCommonUtil.httpsRequest(url,"GET",null));
if(null!=jsonObject){
try{
wechatAccessTokenVo=newWechatAccessTokenVo();
wechatAccessTokenVo.setAccessToken(jsonObject.getString("access_token"));
wechatAccessTokenVo.setExpiresIn(jsonObject.getInteger("expires_in"));
wechatAccessTokenVo.setRefreshToken(jsonObject.getString("refresh_token"));
wechatAccessTokenVo.setOpenId(jsonObject.getString("openid"));
wechatAccessTokenVo.setScope(jsonObject.getString("scope"));
wechatAccessTokenVo.setUnionid(jsonObject.getString("unionid"));
}catch(Exceptione){
wechatAccessTokenVo=null;
interrorCode=jsonObject.getInteger("errcode");
StringerrorMsg=jsonObject.getString("errmsg");
log.error("获取网页授权凭证失败errcode:{}errmsg:{}",errorCode,errorMsg);
}
}
returnwechatAccessTokenVo;
}
/**
*3.通过网页授权获取用户信息
*
*@paramaccessToken网页授权接口调用凭证
*@paramopenId用户标识
*@returnSNSUserInfo
*/
@SuppressWarnings({"deprecation","unchecked"})
publicstaticWechatSNSUserInfoVogetSNSUserInfo(StringaccessToken,StringopenId){
WechatSNSUserInfoVosnsUserInfo=null;
//拼接请求地址发送https请求
Stringurl="https://api./sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID";
url=url.replace("ACCESS_TOKEN",accessToken);
url=url.replace("OPENID",openId);
//通过网页授权获取用户信息
JSONObjectjsonObject=WechatCommonUtil.httpsRequest(url,"GET",null);
if(null!=jsonObject){
try{
snsUserInfo=newWechatSNSUserInfoVo();
//用户的标识
snsUserInfo.setOpenId(jsonObject.getString("openid"));
//昵称
snsUserInfo.setNickname(jsonObject.getString("nickname"));
//性别(1是男性,2是女性,0是未知)
snsUserInfo.setSex(jsonObject.getInteger("sex"));
//用户所在国家
snsUserInfo.setCountry(jsonObject.getString("country"));
//用户所在省份
snsUserInfo.setProvince(jsonObject.getString("province"));
//用户所在城市
snsUserInfo.setCity(jsonObject.getString("city"));
//用户头像
snsUserInfo.setHeadImgUrl(jsonObject.getString("headimgurl"));
//用户特权信息
snsUserInfo.setPrivilegeList(JSONArray.toJavaObject(jsonObject.getJSONArray("privilege"),List.class));
}catch(Exceptione){
snsUserInfo=null;
interrorCode=jsonObject.getInteger("errcode");
StringerrorMsg=jsonObject.getString("errmsg");
log.error("获取用户信息失败errcode:{}errmsg:{}",errorCode,errorMsg);
}
}
returnsnsUserInfo;
}
/**
*刷新授权调用token
*@paramappId开发平台应用唯一标识
*@paramrefreshToken通过access_token获取到的refresh_token参数
*/
publicstaticWechatAccessTokenVorefreshAccessToken(StringappId,StringrefreshToken){
WechatAccessTokenVowechatAccessTokenVo=null;
//拼接微信刷新accessToken请求的链接
Stringurl="https://api./sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN";
url=url.replace("APPID",appId);
url=url.replace("REFRESH_TOKEN",refreshToken);
//获取网页授权凭证发送https请求
JSONObjectjsonObject=WechatCommonUtil.httpsRequest(url,"GET",null);
if(null!=jsonObject){
try{
wechatAccessTokenVo=newWechatAccessTokenVo();
wechatAccessTokenVo.setAccessToken(jsonObject.getString("access_token"));
wechatAccessTokenVo.setExpiresIn(jsonObject.getInteger("expires_in"));
wechatAccessTokenVo.setRefreshToken(jsonObject.getString("refresh_token"));
wechatAccessTokenVo.setOpenId(jsonObject.getString("openid"));
wechatAccessTokenVo.setScope(jsonObject.getString("scope"));
}catch(Exceptione){
wechatAccessTokenVo=null;
interrorCode=jsonObject.getInteger("errcode");
StringerrorMsg=jsonObject.getString("errmsg");
log.error("获取网页授权凭证失败errcode:{}errmsg:{}",errorCode,errorMsg);
}
}
returnwechatAccessTokenVo;
}
}
mon.utils.wechat;
.ssl.X509TrustManager;
importjava.security.cert.CertificateException;
importjava.security.cert.X509Certificate;
/**
*类名:MyX509TrustManager*描述:信任管理器*开发人员:weining*创建时间:/5/5*/
publicclassWechatX509TrustManagerimplementsX509TrustManager{
//检查客户端证书
publicvoidcheckClientTrusted(X509Certificate[]x509Certificates,Strings)throwsCertificateException{
}
//检查服务器端证书
publicvoidcheckServerTrusted(X509Certificate[]x509Certificates,Strings)throwsCertificateException{
}
//返回受信任的X509证书数组
publicX509Certificate[]getAcceptedIssuers(){
returnnewX509Certificate[0];
}
}
最后就是controller控制层代码:
/**
*确认请求来自微信服务器微信的回调
*/
@RequestMapping(value="/oauthtest",method=RequestMethod.GET)
publicStringOAuthTest(HttpServletRequestrequest,HttpServletResponseresponse,Modelmodel)throwsServletException,IOException{
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
PrintWriterout=response.getWriter();
//用户同意授权后,能获取到code
Stringcode=request.getParameter("code");
Stringstate=request.getParameter("state");
//用户同意授权
if(!"authdeny".equals(code)){
//获取网页授权access_token
WechatAccessTokenVowechatAccessTokenVo=WechatOAuthProcessUtil.getOauthAccessToken(code);
if(null==wechatAccessTokenVo){
if(state.equals("register")){
return"redirect:/system/wechatregisterpage";
}
return"redirect:/system/loginpage";
}
//网页授权接口访问凭证
StringaccessToken=wechatAccessTokenVo.getAccessToken();
//用户标识
StringopenId=wechatAccessTokenVo.getOpenId();
//获取用户信息
WechatSNSUserInfoVosnsUserInfo=WechatOAuthProcessUtil.getSNSUserInfo(accessToken,openId);
Mapmap=newHashMap<>();
map.put("wechatAccessTokenVo",wechatAccessTokenVo);
map.put("snsUserInfo",snsUserInfo);
Strings=JSON.toJSONString(map);
//用户unionid
StringunionId=snsUserInfo.getUnionid();
//把字符串存redis里面
RedisUtil.set("WeChat"+unionId,s);
//访问数据库操作
//直接登录
return"登录页";
}
returnnull;
}
到这里java基于微信开放平台的授权登录功能就完成了。