带网站的图片素材,网站整合营销等服务,政元软件做网站,化妆品网站设计报告目录 前言小程序登录步骤说明前端效果涉及到的接口登录凭证#xff1a;wx.login获取用户信息#xff1a;wx.getUserInfo 后端涉及到接口小程序登录 代码展示 微信扫码登录 前言
微信官方文档#xff0c;需要对接哪个模块就从哪里进入。 由于本次我们需要的是小程序的登录。… 目录 前言小程序登录步骤说明前端效果涉及到的接口登录凭证wx.login获取用户信息wx.getUserInfo 后端涉及到接口小程序登录 代码展示 微信扫码登录 前言
微信官方文档需要对接哪个模块就从哪里进入。 由于本次我们需要的是小程序的登录。所以就选择第一个。
介绍一下 API 和 服务端
小程序登录
步骤说明
小程序登录步骤
开发者客户端调用 wx.login() 获取 临时登录凭证code 并回传到开发者服务器。开发者服务器 调用 auth.code2Session 接口换取 用户唯一标识 OpenID 、 用户在微信开放平台账号下的唯一标识UnionID若当前小程序已绑定到微信开放平台账号 和 会话密钥 session_key。
如果需要的话开发者客户端 可以调用 wx.getUserInfo 获取到 code 和 encryptedData, iv再传回给 开发者服务器去进行解密解密成功后就可以拿到 用户信息。
前端
效果
用户信息功能页中注明
用户信息功能页用于帮助插件获取用户信息包括 openid 和昵称等相当于 wx.login 和 wx.getUserInfo 的功能。
在基础库版本 2.3.1 前用户信息功能页是插件中唯一的获取 code 和用户信息的方式
自基础库版本 2.3.1 起用户在该功能页中进行过授权后插件可以直接调用 wx.login 和 wx.getUserInfo
涉及到的接口
登录凭证wx.login 获取用户信息wx.getUserInfo 后端
以Java代码为展示。
涉及到接口
小程序登录 代码展示
可以参考链接https://blog.51cto.com/u_16099229/7857781
从前面可以得到前端会返回给后端一些数据。所以就新建一个实体类来进行接受数据。
Data
public class WechatMPLoginParams {/*** uuid 用户uuid* code 微信返回code 用于与微信交互获取openid 等信息* encryptedData 微信返回加密信息* iv 微信返回* image 微信头像* nickname 微信用户昵称*/private String uuid, code, encryptedData, iv, image, nickName;
}yaml配置
wechat:AppID: AppSecret: 依赖 hutool-all.version5.7.18/hutool-all.versiondependencygroupIdcn.hutool/groupIdartifactIdhutool-all/artifactIdversion${hutool-all.version}/version/dependency控制层 /*** 小程序自动登录** param params 请求参数* return*/PostMapping(/login/auto-login)ApiOperation(value 小程序自动登录)public AjaxResult autoLogin(RequestBody WechatMPLoginParams params) {return AjaxResult.success(connectService.miniProgramAutoLogin(params));}业务层
Slf4j
Service
public class ConnectServiceImpl extends ServiceImplConnectMapper, Connect implements ConnectService {static final boolean AUTO_REGION true;Value(${wechat.AppID})private String WECHAT_APPID;Value(${wechat.AppSecret})private String WECHAT_APPSECRET;OverrideTransactionalpublic String miniProgramAutoLogin(WechatMPLoginParams params) {HashMap cacheData (HashMap) cache.get(CachePrefix.WECHAT_SESSION_PARAMS.getPrefix() params.getUuid());MapString, String map new HashMap(3);// 1. 这里最重要的是获取到 session key、unionId 、openId // 先从缓存中查看是否已经保存了用户小程序登录的信息if (StringUtils.isEmpty(cacheData)) {// 得到微信小程序联合登陆信息并存进缓存里面getWechatMsgByCache(params, map);} else {// 直接从缓存中获取到微信小程序联合登陆信息map (MapString, String) cacheData;// System.out.println(cache: map.get(openId));}// 2. 微信联合登陆return phoneMpBindAndLogin(map, params, map.get(openId), map.get(unionId));}/*** 微信小程序联合登陆信息并存储session key、unionId 、openId信息* * param params 参数* param map 联合登录信息*/private void getWechatMsgByCache(WechatMPLoginParams params, MapString, String map) {// System.out.println(params.getCode());JSONObject json this.getConnect(params.getCode());// System.out.println(json);// 存储session key、unionId 、openId 后续登录用得到String sessionKey json.getStr(session_key);String unionId json.getStr(unionid);String openId json.getStr(openid);map.put(sessionKey, sessionKey);map.put(unionId, unionId);map.put(openId, openId);cache.put(CachePrefix.WECHAT_SESSION_PARAMS.getPrefix() params.getUuid(), map, 900L);}/*** 通过微信返回等code 获取openid 等信息** param code 微信code* return 微信返回的信息*/public JSONObject getConnect(String code) {
// WechatConnectSettingItem setting getWechatMPSetting();String url https://api.weixin.qq.com/sns/jscode2session? appid WECHAT_APPID secret WECHAT_APPSECRET js_code code grant_typeauthorization_code;// log.info(微信返回等code 获取openid 等信息 url);String content HttpUtils.doGet(url, UTF-8, 100, 1000);// log.info(content);return JSONUtil.parseObj(content);}Transactional(rollbackFor Exception.class)public String phoneMpBindAndLogin(MapString, String map, WechatMPLoginParams params) {String sessionKey map.get(sessionKey);String encryptedData params.getEncryptedData();String iv params.getIv();String unionId map.get(unionId);String openId map.get(openId);// 1. 解密获取用户信息JSONObject userInfo this.getUserInfo(encryptedData, sessionKey, iv);// log.info(联合登陆返回{}, userInfo.toString());// 2. 通过解密获得的电话号码查询是否存在该用户String phone (String) userInfo.get(purePhoneNumber);SysUser user new SysUser();ListSysUser userList sysUserService.selectUserInfoList(user);// 2.1 不存在该用户if (StringUtils.isEmpty(userList)) {throw new Exception(非员工手机号码不允许进行微信绑定登录);}// 2.2 存在该用户LoginUser loginUser new LoginUser();SysUser sysUser userList.get(0) ;BeanUtils.copyProperties(sysUser, loginUser);loginUser.setUser(sysUser);sysUser.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));sysUser.setLoginDate(DateUtils.getNowDate());sysUser.setopenid(openId);sysUser.setUnionId(unionId);sysUserService.updateUserProfile(sysUser);// 3. 生成tokenreturn myTokenService.createToken(loginUser);}/*** 解密获取微信信息** param encryptedData 加密信息* param sessionKey 微信sessionKey* param iv 微信揭秘参数* return 用户信息*/public JSONObject getUserInfo(String encryptedData, String sessionKey, String iv) {log.info(encryptedData:{},sessionKey:{},iv:{}, encryptedData, sessionKey, iv);//被加密的数据byte[] dataByte Base64.getMimeDecoder().decode(encryptedData);//加密秘钥byte[] keyByte Base64.getMimeDecoder().decode(sessionKey);//偏移量byte[] ivByte Base64.getMimeDecoder().decode(iv);try {//如果密钥不足16位那么就补足. 这个if 中的内容很重要int base 16;if (keyByte.length % base ! 0) {int groups keyByte.length / base (keyByte.length % base ! 0 ? 1 : 0);byte[] temp new byte[groups * base];Arrays.fill(temp, (byte) 0);System.arraycopy(keyByte, 0, temp, 0, keyByte.length);keyByte temp;}//初始化Security.addProvider(new BouncyCastleProvider());Cipher cipher Cipher.getInstance(AES/CBC/PKCS7Padding, BC);SecretKeySpec spec new SecretKeySpec(keyByte, AES);AlgorithmParameters parameters AlgorithmParameters.getInstance(AES);parameters.init(new IvParameterSpec(ivByte));//初始化cipher.init(Cipher.DECRYPT_MODE, spec, parameters);byte[] resultByte cipher.doFinal(dataByte);if (null ! resultByte resultByte.length 0) {String result new String(resultByte, StandardCharsets.UTF_8);return JSONUtil.parseObj(result);}} catch (Exception e) {log.error(解密获取微信信息错误, e);}throw new ServiceException(联合第三方登录授权信息错误, 20012);}
} 功能类
package com.higentec.system.common.utils.http;import java.io.*;
import java.net.*;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.higentec.system.common.constant.Constants;
import com.higentec.system.common.utils.StringUtils;/*** 通用http发送方法* * author higentec*/
public class HttpUtils
{private static final Logger log LoggerFactory.getLogger(HttpUtils.class);/*** 向指定 URL 发送GET方法的请求** param url 发送请求的 URL* return 所代表远程资源的响应结果*/public static String sendGet(String url){return sendGet(url, StringUtils.EMPTY);}/*** 向指定 URL 发送GET方法的请求** param url 发送请求的 URL* param param 请求参数请求参数应该是 name1value1name2value2 的形式。* return 所代表远程资源的响应结果*/public static String sendGet(String url, String param){return sendGet(url, param, Constants.UTF8);}/*** 向指定 URL 发送GET方法的请求** param url 发送请求的 URL* param param 请求参数请求参数应该是 name1value1name2value2 的形式。* param contentType 编码类型* return 所代表远程资源的响应结果*/public static String sendGet(String url, String param, String contentType){StringBuilder result new StringBuilder();BufferedReader in null;try{String urlNameString StringUtils.isNotBlank(param) ? url ? param : url;log.info(sendGet - {}, urlNameString);URL realUrl new URL(urlNameString);URLConnection connection realUrl.openConnection();connection.setRequestProperty(accept, */*);connection.setRequestProperty(connection, Keep-Alive);connection.setRequestProperty(user-agent, Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1));connection.connect();in new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));String line;while ((line in.readLine()) ! null){result.append(line);}log.info(recv - {}, result);}catch (ConnectException e){log.error(调用HttpUtils.sendGet ConnectException, url url ,param param, e);}catch (SocketTimeoutException e){log.error(调用HttpUtils.sendGet SocketTimeoutException, url url ,param param, e);}catch (IOException e){log.error(调用HttpUtils.sendGet IOException, url url ,param param, e);}catch (Exception e){log.error(调用HttpsUtil.sendGet Exception, url url ,param param, e);}finally{try{if (in ! null){in.close();}}catch (Exception ex){log.error(调用in.close Exception, url url ,param param, ex);}}return result.toString();}/*** 向指定 URL 发送POST方法的请求** param url 发送请求的 URL* param param 请求参数请求参数应该是 name1value1name2value2 的形式。* return 所代表远程资源的响应结果*/public static String sendPost(String url, String param){PrintWriter out null;BufferedReader in null;StringBuilder result new StringBuilder();try{String urlNameString url;log.info(sendPost - {}, urlNameString);URL realUrl new URL(urlNameString);URLConnection conn realUrl.openConnection();conn.setRequestProperty(accept, */*);conn.setRequestProperty(connection, Keep-Alive);conn.setRequestProperty(user-agent, Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1));conn.setRequestProperty(Accept-Charset, utf-8);conn.setRequestProperty(contentType, utf-8);conn.setDoOutput(true);conn.setDoInput(true);out new PrintWriter(conn.getOutputStream());out.print(param);out.flush();in new BufferedReader(new InputStreamReader(conn.getInputStream(), utf-8));String line;while ((line in.readLine()) ! null){result.append(line);}log.info(recv - {}, result);}catch (ConnectException e){log.error(调用HttpUtils.sendPost ConnectException, url url ,param param, e);}catch (SocketTimeoutException e){log.error(调用HttpUtils.sendPost SocketTimeoutException, url url ,param param, e);}catch (IOException e){log.error(调用HttpUtils.sendPost IOException, url url ,param param, e);}catch (Exception e){log.error(调用HttpsUtil.sendPost Exception, url url ,param param, e);}finally{try{if (out ! null){out.close();}if (in ! null){in.close();}}catch (IOException ex){log.error(调用in.close Exception, url url ,param param, ex);}}return result.toString();}public static String sendSSLPost(String url, String param){StringBuilder result new StringBuilder();String urlNameString url ? param;try{log.info(sendSSLPost - {}, urlNameString);SSLContext sc SSLContext.getInstance(SSL);sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());URL console new URL(urlNameString);HttpsURLConnection conn (HttpsURLConnection) console.openConnection();conn.setRequestProperty(accept, */*);conn.setRequestProperty(connection, Keep-Alive);conn.setRequestProperty(user-agent, Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1));conn.setRequestProperty(Accept-Charset, utf-8);conn.setRequestProperty(contentType, utf-8);conn.setDoOutput(true);conn.setDoInput(true);conn.setSSLSocketFactory(sc.getSocketFactory());conn.setHostnameVerifier(new TrustAnyHostnameVerifier());conn.connect();InputStream is conn.getInputStream();BufferedReader br new BufferedReader(new InputStreamReader(is));String ret ;while ((ret br.readLine()) ! null){if (ret ! null !.equals(ret.trim())){result.append(new String(ret.getBytes(ISO-8859-1), utf-8));}}log.info(recv - {}, result);conn.disconnect();br.close();}catch (ConnectException e){log.error(调用HttpUtils.sendSSLPost ConnectException, url url ,param param, e);}catch (SocketTimeoutException e){log.error(调用HttpUtils.sendSSLPost SocketTimeoutException, url url ,param param, e);}catch (IOException e){log.error(调用HttpUtils.sendSSLPost IOException, url url ,param param, e);}catch (Exception e){log.error(调用HttpsUtil.sendSSLPost Exception, url url ,param param, e);}return result.toString();}private static class TrustAnyTrustManager implements X509TrustManager{Overridepublic void checkClientTrusted(X509Certificate[] chain, String authType){}Overridepublic void checkServerTrusted(X509Certificate[] chain, String authType){}Overridepublic X509Certificate[] getAcceptedIssuers(){return new X509Certificate[] {};}}/*** get 请求 静态方法** param link* param encoding* return*/public static String doGet(String link, String encoding, int connectTimeout, int readTimeout) {HttpURLConnection conn null;try {URL url new URL(link);conn (HttpURLConnection) url.openConnection();conn.setRequestMethod(GET);conn.setConnectTimeout(connectTimeout);conn.setReadTimeout(readTimeout);BufferedInputStream in new BufferedInputStream(conn.getInputStream());ByteArrayOutputStream out new ByteArrayOutputStream();byte[] buf new byte[1024];for (int i 0; (i in.read(buf)) 0; ) {out.write(buf, 0, i);}out.flush();String s out.toString(encoding);return s;} catch (Exception e) {throw new RuntimeException(e.getMessage(), e);} finally {if (conn ! null) {conn.disconnect();conn null;}}}private static class TrustAnyHostnameVerifier implements HostnameVerifier{Overridepublic boolean verify(String hostname, SSLSession session){return true;}}
}如果需要单独从微信小程序获取用户手机号码可参考
微信开发文档—— 获取手机号详细教程微信小程序获取用户手机号码教程前端后端https://blog.csdn.net/qq_51235856/article/details/131158254
微信扫码登录
微信登录——授权登录获取用户信息https://blog.csdn.net/YXXXYX/article/details/127338450