微信授权并登陆
记录自己第一次写微信授权后的成果,以便后续查找学习。
参考文档:
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参数:appIdsecretcode
通过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_tokenopenid
通过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 {@Autowiredprivate IZzInstitutionGzhInfoService zzInstitutionGzhInfoService;@Autowiredprivate WxTokenService wxTokenService;@Autowiredprivate ISysUserService sysUserService;@Autowiredprivate 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 获取openidweiXinOauth2Token = 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();// 根据用户名和密码生成tokenString 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*/@Overridepublic 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*/@Overridepublic 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;}}