微信开放平台基于网站应用授权登录源码(java)
程序员文章站
2023-12-22 23:35:58
...
话不多说,直奔主题。
首先需要有个网站应用:(没有的可以创建)
接下来我们打开微信开放平台官网,找到资源中心>网站应用>微信登录功能>网站应用微信登录开发指南:
网站登录AppId和AppSecret查看方式:
授权流程说明:
微信OAuth2.0授权登录让微信用户使用微信身份安全登录第三方应用或网站,在微信用户授权登录已接入微信OAuth2.0的第三方应用后,第三方可以获取到用户的接口调用凭证(access_token),通过access_token可以进行微信开放平台授权关系接口调用,从而可实现获取微信用户基本开放信息和帮助用户实现基础开放功能等。
微信OAuth2.0授权登录目前支持authorization_code模式,适用于拥有server端的应用授权。该模式整体流程为:
-
1. 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据code参数;
-
2. 通过code参数加上AppID和AppSecret等,通过API换取access_token;
-
3. 通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。
-
获取access_token时序图:
微信网站应用授权登录接口对接代码实现:
需用的配置文件:
需用的vo类:
代码:
package com.thinkwin.common.vo;
/**
* 类名: WechatAccessTokenVo
* 描述: 授权关系接口的调用凭证模型
* 开发人员:dell
* 创建时间: 2017/5/5
*/
public class WechatAccessTokenVo{
// 网页授权接口调用凭证
private String accessToken ;
// 凭证有效时长
private int expiresIn;
// 用于刷新凭证
private String refreshToken;
// 用户标识
private String openId;
// 用户授权作用域
private String scope;
// 用户全局唯一标识 unionid
private String unionid;
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public int getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(int expiresIn) {
this.expiresIn = expiresIn;
}
public String getRefreshToken() {
return refreshToken;
}
public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
public String getOpenId() {
return openId;
}
public void setOpenId(String openId) {
this.openId = openId;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public String getUnionid() {
return unionid;
}
public void setUnionid(String unionid) {
this.unionid = unionid;
}
}
package com.thinkwin.common.vo;
import java.util.List;
/**
* 类名: WechatSNSUserInfoVo
* 描述: 通过网页授权获取的用户信息
* 开发人员: dell
* 创建时间: 2017/4/27
*/
public class WechatSNSUserInfoVo {
// 用户标识
private String openId;
// 用户昵称
private String nickname;
// 性别(1是男性,2是女性,0是未知)
private int sex;
// 国家
private String country;
// 省份
private String province;
// 城市
private String city;
// 用户头像链接
private String headImgUrl;
// 用户特权信息
private List privilegeList;
// 用户全局唯一标识 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 int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
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 getHeadImgUrl() {
return headImgUrl;
}
public void setHeadImgUrl(String headImgUrl) {
this.headImgUrl = headImgUrl;
}
public List getPrivilegeList() {
return privilegeList;
}
public void setPrivilegeList(List privilegeList) {
this.privilegeList = privilegeList;
}
public String getUnionid() {
return unionid;
}
public void setUnionid(String unionid) {
this.unionid = unionid;
}
}
需要的工具类:
代码 :
package com.thinkwin.common.utils.wechat;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.URL;
/**
* 类名: WechatCommonUtil
* 描述: 微信登录通用工具类
* 开发人员: dell
* 创建时间: 2017/5/5
*/
public class WechatCommonUtil {
private static Logger log = LoggerFactory.getLogger(WechatCommonUtil.class);
/**
* 发送https请求
*
* @param requestUrl 请求地址
* @param requestMethod 请求方式(GET、POST)
* @param outputStr 提交的数据
* @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
*/
public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {
JSONObject jsonObject = null;
try {
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = { new WechatX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection conn = (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) {
OutputStream outputStream = conn.getOutputStream();
// 注意编码格式
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = conn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
StringBuffer buffer = new StringBuffer();
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
// 释放资源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
conn.disconnect();
jsonObject = JSONObject.parseObject(buffer.toString());
} catch (ConnectException ce) {
log.error("连接超时:{}", ce);
} catch (Exception e) {
log.error("https请求异常:{}", e);
}
return jsonObject;
}
}
package com.thinkwin.common.utils.wechat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* 类名: WechatConfigLoader
* 描述: 微信初始化配置信息
* 开发人员: dell
* 创建时间: 2017/5/5
*/
public class WechatConfigLoader {
//日志记录对象
private static Logger log = LoggerFactory.getLogger(WechatConfigLoader.class);
//配置文件路径
private static String wechatPath = "wechat.properties";
//开发平台应用唯一标识
private static String appId;
//开放平台应用**
private static String appSecret;
//微信第三方回调地址
private static String backUrl;
static {
// 类初始化后加载配置文件
InputStream in = WechatConfigLoader.class.getClassLoader()
.getResourceAsStream(wechatPath);
Properties props = new Properties();
try {
props.load(in);
} catch (IOException e) {
log.error("load wechat setting error,pleace check the file path:"
+ wechatPath);
log.error(e.toString(), e);
}
appId = props.getProperty("wechat.appId");
appSecret = props.getProperty("wechat.appSecret");
backUrl = props.getProperty("wechat.backUrl");
log.debug("load wechat setting success,file path:" + wechatPath);
}
public static String getAppId() {
return appId;
}
public static String getAppSecret() {
return appSecret;
}
public static String getBackUrl() {
return backUrl;
}
public static void setWechatPath(String wechatPath) {
WechatConfigLoader.wechatPath = wechatPath;
}
public static String getWechatPath() {
return wechatPath;
}
public static void setAppId(String appId) {
WechatConfigLoader.appId = appId;
}
public static void setAppSecret(String appSecret) {
WechatConfigLoader.appSecret = appSecret;
}
public static void setBackUrl(String backUrl) {
WechatConfigLoader.backUrl = backUrl;
}
}
package com.thinkwin.lehui.common.wechatUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.thinkwin.lehui.common.wechatVo.WechatAccessTokenVo;
import com.thinkwin.lehui.common.wechatVo.WechatSNSUserInfoVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
/**
* 类名: WXOAuthProcess
* 描述: 微信第三方登录授权流程工具类
* 开发人员: dell
* 创建时间: 2017/5/5
*/
public class WechatOAuthProcessUtil {
private static Logger log = LoggerFactory.getLogger(WechatOAuthProcessUtil.class);
/**
* 1.获取授权code
* @param req
* @param resp
*/
public static void getOAuthCode(HttpServletRequest req, HttpServletResponse resp){
String appId = WechatConfigLoader.getAppId();
String backUrl = WechatConfigLoader.getBackUrl();
String url="https://open.weixin.qq.com/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 (IOException e) {
e.printStackTrace();
}
}
/**
* 2.获取授权调用token
* @param appId 开发平台应用唯一标识
* @param appSecret 开放平台应用**
* @param code 授权临时票据 根据code来换取accessToken
*/
public static WechatAccessTokenVo getOauthAccessToken(String appId, String appSecret, String code){
WechatAccessTokenVo wechatAccessTokenVo = null;
//拼接微信获取accessToken请求的链接
String url = "https://api.weixin.qq.com/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请求
JSONObject jsonObject = (WechatCommonUtil.httpsRequest(url, "GET", null));
if (null != jsonObject) {
try {
wechatAccessTokenVo = new WechatAccessTokenVo();
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 (Exception e) {
wechatAccessTokenVo = null;
int errorCode = jsonObject.getInteger("errcode");
String errorMsg = jsonObject.getString("errmsg");
log.error("获取网页授权凭证失败 errcode:{} errmsg:{}", errorCode, errorMsg);
}
}
return wechatAccessTokenVo;
}
/**
* 3.通过网页授权获取用户信息
*
* @param accessToken 网页授权接口调用凭证
* @param openId 用户标识
* @return SNSUserInfo
*/
@SuppressWarnings( { "deprecation", "unchecked" })
public static WechatSNSUserInfoVo getSNSUserInfo(String accessToken, String openId) {
WechatSNSUserInfoVo snsUserInfo = null;
// 拼接请求地址 发送https请求
String url = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID";
url = url.replace("ACCESS_TOKEN", accessToken);
url = url.replace("OPENID", openId);
// 通过网页授权获取用户信息
JSONObject jsonObject = WechatCommonUtil.httpsRequest(url, "GET", null);
if (null != jsonObject) {
try {
snsUserInfo = new WechatSNSUserInfoVo();
// 用户的标识
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 (Exception e) {
snsUserInfo = null;
int errorCode = jsonObject.getInteger("errcode");
String errorMsg = jsonObject.getString("errmsg");
log.error("获取用户信息失败 errcode:{} errmsg:{}", errorCode, errorMsg);
}
}
return snsUserInfo;
}
/**
* 刷新授权调用token
* @param appId 开发平台应用唯一标识
* @param refreshToken 通过access_token获取到的refresh_token参数
*/
public static WechatAccessTokenVo refreshAccessToken(String appId, String refreshToken){
WechatAccessTokenVo wechatAccessTokenVo = null;
//拼接微信刷新accessToken请求的链接
String url = "https://api.weixin.qq.com/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请求
JSONObject jsonObject = WechatCommonUtil.httpsRequest(url, "GET", null);
if (null != jsonObject) {
try {
wechatAccessTokenVo = new WechatAccessTokenVo();
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 (Exception e) {
wechatAccessTokenVo = null;
int errorCode = jsonObject.getInteger("errcode");
String errorMsg = jsonObject.getString("errmsg");
log.error("获取网页授权凭证失败 errcode:{} errmsg:{}", errorCode, errorMsg);
}
}
return wechatAccessTokenVo;
}
}
package com.thinkwin.common.utils.wechat;
import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* 类名: MyX509TrustManager
* 描述: 信任管理器
* 开发人员: dell
* 创建时间: 2017/5/5
*/
public class WechatX509TrustManager implements X509TrustManager {
// 检查客户端证书
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
// 检查服务器端证书
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
// 返回受信任的X509证书数组
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
最后就是controller控制层代码:
/**
* 确认请求来自微信服务器 微信的回调
*/
@RequestMapping(value = "/oauthtest", method = RequestMethod.GET)
public String OAuthTest(HttpServletRequest request, HttpServletResponse response, Model model) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
// 用户同意授权后,能获取到code
String code = request.getParameter("code");
String state = request.getParameter("state");
// 用户同意授权
if (!"authdeny".equals(code)) {
// 获取网页授权access_token
WechatAccessTokenVo wechatAccessTokenVo = WechatOAuthProcessUtil.getOauthAccessToken(code);
if(null == wechatAccessTokenVo){
if(state.equals("register")){
return "redirect:/system/wechatregisterpage";
}
return "redirect:/system/loginpage";
}
// 网页授权接口访问凭证
String accessToken = wechatAccessTokenVo.getAccessToken();
// 用户标识
String openId = wechatAccessTokenVo.getOpenId();
// 获取用户信息
WechatSNSUserInfoVo snsUserInfo = WechatOAuthProcessUtil.getSNSUserInfo(accessToken, openId);
Map map = new HashMap<>();
map.put("wechatAccessTokenVo",wechatAccessTokenVo);
map.put("snsUserInfo",snsUserInfo);
String s = JSON.toJSONString(map);
// 用户unionid
String unionId = snsUserInfo.getUnionid();
//把字符串存redis里面
RedisUtil.set("WeChat"+unionId,s);
//访问数据库操作
//直接登录
return "登录页";
}
return null;
}
到这里java基于微信开放平台的授权登录功能就完成了。