微信授權並登陸
阿新 • • 發佈:2021-01-27
微信授權並登陸
記錄自己第一次寫微信授權後的成果,以便後續查詢學習。
參考文件:
https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
1. 先確認接收的引數
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state= STATE#wechat_redirect
授權會呼叫這個網址,使用者同意授權後重定向到redirect_uri(即為後臺授權的介面路徑)處,後臺可以接收到兩個引數:code和state;通過code可以獲取使用者openid,state中可以存放自己需要的引數,也可以不存,通過下方方式獲取:
String code = request.getParameter("code");
String appid = request.getParameter("state");
在這裡因為我的appid需要動態獲取,所以把appid放在了state中。
2. 通過code換取網頁授權access_token
網址:https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
引數:appId
secret
code
通過get請求呼叫這個網址後得到JSONObject物件,可以得到access_token和openid:
WeiXinOauth2Token weiXinOauth2Token = new WeiXinOauth2Token();
weiXinOauth2Token.setAccessToken (jsonObject.getString("access_token"));//網頁授權介面呼叫憑證
weiXinOauth2Token.setExpiresIn(jsonObject.getInt("expires_in"));//access_token介面呼叫憑證超時時間,單位(秒)
weiXinOauth2Token.setRefreshToken(jsonObject.getString("refresh_token"));//使用者重新整理access_token
weiXinOauth2Token.setOpenId(jsonObject.getString("openid"));//使用者唯一標識
weiXinOauth2Token.setScope(jsonObject.getString("scope"));//使用者授權的作用域,使用逗號(,)分隔
3. 根據accessToken openid 獲得使用者資訊
網址:https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
引數:access_token
openid
通過get請求呼叫這個網址後得到JSONObject物件,可以得到使用者的基本資訊:
WeChatUser weChatUser =new WeChatUser();
weChatUser.setOpenid(jsonObject.getString("openid"));//使用者的唯一標識
weChatUser.setNickName(jsonObject.getString("nickname"));//使用者暱稱
weChatUser.setSex(jsonObject.getString("sex"));//使用者的性別,值為1時是男性,值為2時是女性,值為0時是未知
weChatUser.setProvince(jsonObject.getString("province"));//使用者個人資料填寫的省份
weChatUser.setCity(jsonObject.getString("city"));//普通使用者個人資料填寫的城市
if (jsonObject.getString("headimgurl") != null
&& !jsonObject.getString("headimgurl").toString().trim().equals("")) {//使用者頭像
weChatUser.setHeadImgUrl(jsonObject.getString("headimgurl"));
} else {
weChatUser.setHeadImgUrl("");
}
StringBuffer privilege = null;//使用者特權資訊,json 陣列,這裡為了方便寫成了String型別的
List<String> privilegeList = JSONArray.toList(jsonObject.getJSONArray("privilege"), List.class);
for (int i = 0; i < privilegeList.size();i ++) {
if (i != privilegeList.size() - 1) {
privilege.append(privilegeList.get(i)+",");
} else {
privilege.append(privilegeList.get(i));
}
}
weChatUser.setPrivilege(privilege.toString());
if (jsonObject.get("unionid") != null) {//只有在使用者將公眾號繫結到微信開放平臺帳號後,才會出現該欄位
weChatUser.setUnionId(jsonObject.getString("unionid"));
}
4. 登陸
使用者授權獲取使用者基本資訊後儲存到使用者表,生成使用者的使用者名稱和密碼:
sysUser.setUsername(weChatUser.getNickName());
String salt = oConvertUtils.randomGen(8);
sysUser.setSalt(salt);
String passwordEncode = PasswordUtil.encrypt(sysUser.getUsername(), weChatUser.getOpenid().substring(weChatUser.getOpenid().length() - 6, weChatUser.getOpenid().length()) + "123456&", salt);
sysUser.setPassword(passwordEncode);
根據使用者名稱和密碼產生token,存到redis中,然後重定向到首頁:
String password = sysUser.getPassword();
String username = sysUser.getUsername();
// 生成token
String token = JwtUtil.sign(username,password);
redisUtil.set("openID" + token, sysUser.getOpenId());
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
// 設定超時時間
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 1000);
redisUtil.expire("openID" + token, JwtUtil.EXPIRE_TIME / 1000);
// 重定向到首頁
response.sendRedirect("");
附:全部後端程式碼
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.util.PasswordUtil;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.business.entity.WeChatUser;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysUserService;
import org.jeecg.modules.weixin.entity.ZzInstitutionGzhInfo;
import org.jeecg.modules.weixin.service.IZzInstitutionGzhInfoService;
import org.jeecg.modules.weixin.service.WxTokenService;
import org.jeecg.modules.weixin.vo.WeiXinOauth2Token;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@RestController
@RequestMapping("/weixin")
@Api(tags = "微信介面")
@Slf4j
public class WeiXinUserController {
@Autowired
private IZzInstitutionGzhInfoService zzInstitutionGzhInfoService;
@Autowired
private WxTokenService wxTokenService;
@Autowired
private ISysUserService sysUserService;
@Autowired
private RedisUtil redisUtil;
@RequestMapping(value = "/wxAuthorize", method = RequestMethod.GET)
@ApiOperation("微信授權獲取使用者資訊並登陸")
public Result<WeChatUser> wxAuthorize(HttpServletRequest request, HttpServletResponse response) {
Result<WeChatUser> result = new Result<>();
try {
String code = request.getParameter("code");
String appid = request.getParameter("state");
log.info("========appid="+appid);
WeiXinOauth2Token weiXinOauth2Token = null;
if (StringUtils.isNotBlank(code)) {
// state中儲存的是appid,根據appid去表中查詢該機構的secret
// 此處是因為我的appid和secret需要動態獲取,所以進行查詢,如果不需要動態獲取可以省略此步驟
ZzInstitutionGzhInfo zzInstitutionGzhInfo = zzInstitutionGzhInfoService.getInstitutionGzhInfo(appid);
// 根據 appid secret code 獲取openid
weiXinOauth2Token = wxTokenService.getOauth2AccessToken(appid, zzInstitutionGzhInfo.getAppSecret(), code);
log.info("========weiXinOauth2Token{}",weiXinOauth2Token);
if (weiXinOauth2Token != null) {
String accessToken = weiXinOauth2Token.getAccessToken();
log.info("==========accessToken="+accessToken);
String openid = weiXinOauth2Token.getOpenId();
// 根據accessToken openid 獲得使用者資訊
WeChatUser weChatUser = wxTokenService.getSNSUserInfo(accessToken, openid);
// 授權後登陸
SysUser sysUser = sysUserService.getUserByOpenId(openid);
if (sysUser == null) {
// 儲存使用者的基本資訊
sysUser = new SysUser();
sysUser.setOpenId(weChatUser.getOpenid());
sysUser.setNickname(weChatUser.getNickName());
sysUser.setSex(Integer.valueOf(weChatUser.getSex()));
sysUser.setProvince(weChatUser.getProvince());
sysUser.setCity(weChatUser.getCity());
sysUser.setHeadImgUrl(weChatUser.getHeadImgUrl());
sysUser.setPrivilege(weChatUser.getPrivilege());
sysUser.setUnionid(weChatUser.getUnionId());
sysUser.setUsername(weChatUser.getNickName());
// 生成使用者登入的加鹽密碼
// 可以根據自己需要生成密碼,這裡就不再展示
String salt = oConvertUtils.randomGen(8);
sysUser.setSalt(salt);
String passwordEncode = PasswordUtil.encrypt(sysUser.getUsername(), weChatUser.getOpenid().substring(weChatUser.getOpenid().length() - 6, weChatUser.getOpenid().length()) + "123456&", salt);
sysUser.setPassword(passwordEncode);
sysUserService.save(sysUser);
}
String password = sysUser.getPassword();
String username = sysUser.getUsername();
// 根據使用者名稱和密碼生成token
String token = JwtUtil.sign(username,password);
redisUtil.set("appId"+token,appid);
redisUtil.set("openID" + token, sysUser.getOpenId());
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
// 設定超時時間
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 1000);
redisUtil.expire("openID" + token, JwtUtil.EXPIRE_TIME / 1000);
// 重定向到首頁
response.sendRedirect("");
// 這裡返回資料是因為前臺需要,如果不需要可以不寫
result.setResult(weChatUser);
result.success("微信授權獲取使用者資訊並登陸成功");
return result;
} else {
result.setMessage("微信授權獲取使用者資訊並登陸 獲取token為空");
return result;
}
} else {
result.setMessage("微信授權失敗");
return result;
}
} catch (Exception e) {
log.error("微信授權登入失敗", e.getMessage());
}
return result;
}
}
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONArray;
import org.jeecg.modules.business.entity.WeChatUser;
import org.jeecg.modules.weixin.service.WxTokenService;
import org.jeecg.modules.weixin.utils.HttpsX509TrustManager;
import org.jeecg.modules.weixin.vo.WeiXinOauth2Token;
import org.springframework.stereotype.Service;
import net.sf.json.JSONObject;
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;
import java.security.SecureRandom;
import java.util.List;
@Service
@Slf4j
public class WxTokenServiceImpl implements WxTokenService {
/**
* 網頁授權獲取openid
* @param appId
* @param appSecret
* @param code
* @return
*/
@Override
public WeiXinOauth2Token getOauth2AccessToken(String appId, String appSecret, String code) {
WeiXinOauth2Token weiXinOauth2Token = null;
String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
requestUrl = requestUrl.replace("APPID", appId);
requestUrl = requestUrl.replace("SECRET", appSecret);
requestUrl = requestUrl.replace("CODE", code);
JSONObject jsonObject = httpsRequest(requestUrl, "GET", null);
if (jsonObject != null) {
try {
weiXinOauth2Token = new WeiXinOauth2Token();
weiXinOauth2Token.setAccessToken(jsonObject.getString("access_token"));
weiXinOauth2Token.setExpiresIn(jsonObject.getInt("expires_in"));
weiXinOauth2Token.setRefreshToken(jsonObject.getString("refresh_token"));
weiXinOauth2Token.setOpenId(jsonObject.getString("openid"));
weiXinOauth2Token.setScope(jsonObject.getString("scope"));
} catch (Exception e) {
weiXinOauth2Token = null;
int errorCode = jsonObject.getInt("errcode");
String str1 = jsonObject.getString("errmsg");
log.error(e.getMessage());
}
}
return weiXinOauth2Token;
}
private JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {
JSONObject jsonObject = null;
try {
TrustManager[] tm = {new HttpsX509TrustManager()};
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new SecureRandom());
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);
conn.setRequestMethod(requestMethod);
if (outputStr != null) {
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.fromObject(buffer.toString());
} catch (ConnectException localConnectException) {
} catch (Exception localException) {
}
return jsonObject;
}
/**
* 網頁授權獲取使用者資訊
* @param accessToken
* @param openId
* @return
*/
@Override
public WeChatUser getSNSUserInfo(String accessToken, String openId) {
WeChatUser weChatUser = null;
String requestUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID";
requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);
JSONObject jsonObject = httpsRequest(requestUrl,"GET",null);
log.info("=============jsonObject="+jsonObject);
if (jsonObject.getString("errcode") != null) {
} else {
weChatUser =new WeChatUser();
weChatUser.setOpenid(jsonObject.getString("openid"));
weChatUser.setNickName(jsonObject.getString("nickname"));
weChatUser.setSex(jsonObject.getString("sex"));
weChatUser.setProvince(jsonObject.getString("province"));
weChatUser.setCity(jsonObject.getString("city"));
if (jsonObject.getString("headimgurl") != null
&& !jsonObject.getString("headimgurl").toString().trim().equals("")) {
weChatUser.setHeadImgUrl(jsonObject.getString("headimgurl"));
} else {
weChatUser.setHeadImgUrl("");
}
StringBuffer privilege = null;
List<String> privilegeList = JSONArray.toList(jsonObject.getJSONArray("privilege"), List.class);
for (int i = 0; i < privilegeList.size();i ++) {
if (i != privilegeList.size() - 1) {
privilege.append(privilegeList.get(i)+",");
} else {
privilege.append(privilegeList.get(i));
}
}
weChatUser.setPrivilege(privilege.toString());
if (jsonObject.get("unionid") != null) {
weChatUser.setUnionId(jsonObject.getString("unionid"));
}
weChatUser.setIsEnabled("1");
}
return weChatUser;
}
}