springboot+taro实现小程序微信登录并获得手机号授权功能
点击上方 java项目开发,选择 设为星标
优质文章,及时送达
案例功能效果图
获取手机号码登录页面

微信登录授权页面

手机&微信都登录成功页面

环境介绍

前端:taro
后端:springboot
jdk:1.8及以上
数据库:mysql
完整源码获取方式
源码获取方式
扫码关注回复【wxdl】获取完整源码
如果你在运行这个代码的过程中有遇到问题,请加小编微信xxf960513,我拉你进对应微信学习群!!帮助你快速掌握这个功能代码!
核心代码介绍
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0modelVersion><parent><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starter-parentartifactId><version>2.4.1version><relativePath/>parent><groupId>com.examplegroupId><artifactId>wechatartifactId><version>0.0.1-SNAPSHOTversion><name>wechatname><description>Demo project for Spring Bootdescription><properties><skipTests>trueskipTests><java.version>1.8java.version><maven-jar-plugin.version>2.6maven-jar-plugin.version>properties><dependencies><dependency><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starterartifactId>dependency><dependency><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starter-webartifactId>dependency><dependency><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starter-testartifactId><scope>testscope>dependency><dependency><groupId>io.springfoxgroupId><artifactId>springfox-swagger2artifactId><version>2.9.2version>dependency><dependency><groupId>io.swaggergroupId><artifactId>swagger-modelsartifactId><version>1.5.21version>dependency><dependency><groupId>com.github.xiaoymingroupId><artifactId>swagger-bootstrap-uiartifactId><version>1.9.3version>dependency><dependency><groupId>org.apache.httpcomponentsgroupId><artifactId>httpclientartifactId>dependency><dependency><groupId>org.codehaus.xfiregroupId><artifactId>xfire-coreartifactId><version>1.2.6version>dependency><dependency><groupId>org.bouncycastlegroupId><artifactId>bcprov-jdk16artifactId><version>1.46version>dependency><dependency><groupId>com.alibabagroupId><artifactId>fastjsonartifactId><version>1.2.62version>dependency>dependencies><build><plugins><plugin><groupId>org.springframework.bootgroupId><artifactId>spring-boot-maven-pluginartifactId>plugin>plugins>build>project>
WeChatConfig.java
package com.example.wechat.util;/*** Copyright @ 2020 Zonlyn. All rights reserved.* @Description: 该类的功能描述** @version: v1.0.0* @author: ducl* @date: 2020年12月16日 上午9:12:21** Modification History:* Date Author Version Description*---------------------------------------------------------** 2020年12月16日 ducl v1.0.0 修改原因*/public class WeChatConfig{//微信 app_idpublic static final String APP_ID ="your APP_ID";//"wx5a383d14e917d3ae";//app_secretpublic static final String APP_SECRET = "0569d415cc撒打多大9cd6a834763";//获取 session_key地址public static final String USERINFO_URL = "https://api.weixin.qq.com/sns/jscode2session";}
WeChatController.java
package com.example.wechat.ctrler;import java.io.IOException;import java.io.UnsupportedEncodingException;import java.security.AlgorithmParameters;import java.security.InvalidAlgorithmParameterException;import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import java.security.NoSuchProviderException;import java.security.Security;import java.security.spec.InvalidParameterSpecException;import java.util.Arrays;import javax.crypto.BadPaddingException;import javax.crypto.Cipher;import javax.crypto.IllegalBlockSizeException;import javax.crypto.NoSuchPaddingException;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.SecretKeySpec;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.bouncycastle.jce.provider.BouncyCastleProvider;import org.codehaus.xfire.util.Base64;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Controller;import org.springframework.util.StringUtils;import org.springframework.web.bind.annotation.CrossOrigin;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.ResponseBody;import com.alibaba.fastjson.JSONObject;import com.example.wechat.bean.WeChatUserInfo;import com.example.wechat.util.HttpUtil;import com.example.wechat.util.WeChatConfig;import com.example.wechat.util.rest.CodeMsg;import com.example.wechat.util.rest.Result;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;/*** Copyright @ 2020 Zonlyn. All rights reserved.* @Description: 该类的功能描述** @version: v1.0.0* @author: ducl* @date: 2020年12月16日 上午9:03:16** Modification History:* Date Author Version Description*---------------------------------------------------------** 2020年12月16日 ducl v1.0.0 修改原因*/@Controller@RequestMapping("/wechat")@CrossOrigin@Api(value="微信小程序服务",tags={"微信小程序服务"})public class WeChatController{private Logger logger =LoggerFactory.getLogger(WeChatController.class);@RequestMapping(value = "/dec/userinfo", method = RequestMethod.POST)@ResponseBody@ApiOperation(value="解析登录成功用户信息")public Object login(@RequestBody WeChatUserInfo infoData, HttpServletRequest request, HttpServletResponse response)throws IOException {logger.info("请求的数据:[{}]" + infoData);//JSONObject dataObj = JSONObject.parseObject(infoData);String code = infoData.getCode();String encryptedData = infoData.getEncrypted_data();String iv = infoData.getIv();boolean paramError = StringUtils.isEmpty(code) || StringUtils.isEmpty(encryptedData) || StringUtils.isEmpty(iv);if(paramError) {return Result.error(CodeMsg.PARAMERROR);}String sessionkey = getSessionKey(code);JSONObject userInfo = this.getUserInfo(encryptedData, sessionkey, iv);logger.info("解析出的用户信息:[{}]",userInfo);return Result.success(userInfo);}private String getSessionKey(String code) {logger.info("我的APP_ID:[{}]",WeChatConfig.APP_ID);String url = WeChatConfig.USERINFO_URL+"?appid=" + WeChatConfig.APP_ID + "&secret="+ WeChatConfig.APP_SECRET + "&js_code=" + code + "&grant_type=authorization_code";String reusult = HttpUtil.sendGet(url, true);JSONObject oppidObj = JSONObject.parseObject(reusult);//String openid = (String) oppidObj.get("openid");String session_key = (String) oppidObj.get("session_key");return session_key;}/*** 获取信息*/private JSONObject getUserInfo(String encryptedData,String sessionkey,String iv){// 被加密的数据byte[] dataByte = Base64.decode(encryptedData);// 加密秘钥byte[] keyByte = Base64.decode(sessionkey);// 偏移量byte[] ivByte = Base64.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, "UTF-8");return JSONObject.parseObject(result);}} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (NoSuchPaddingException e) {e.printStackTrace();} catch (InvalidParameterSpecException e) {e.printStackTrace();} catch (IllegalBlockSizeException e) {e.printStackTrace();} catch (BadPaddingException e) {e.printStackTrace();} catch (UnsupportedEncodingException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (InvalidAlgorithmParameterException e) {e.printStackTrace();} catch (NoSuchProviderException e) {e.printStackTrace();}return null;}}
HttpUtil.java
åpackage com.example.wechat.util;import java.security.cert.CertificateException;import java.security.cert.X509Certificate;import java.util.ArrayList;import java.util.List;import java.util.Map;import javax.net.ssl.SSLContext;import org.apache.http.NameValuePair;import org.apache.http.client.config.RequestConfig;import org.apache.http.client.entity.UrlEncodedFormEntity;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.client.methods.HttpPost;import org.apache.http.client.methods.HttpRequestBase;import org.apache.http.conn.ssl.SSLConnectionSocketFactory;import org.apache.http.conn.ssl.SSLContextBuilder;import org.apache.http.conn.ssl.TrustStrategy;import org.apache.http.entity.StringEntity;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClientBuilder;import org.apache.http.message.BasicNameValuePair;import org.apache.http.util.EntityUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/*** @description httpclient 工具* @author Administrator**/("deprecation")public class HttpUtil{private static Logger logger = LoggerFactory.getLogger(HttpUtil.class);private static final int Format_KeyValue = 0;private static final int Format_Json = 1;private static final int SOCKET_TIMEOUT = 60 * 1000;private static final int CONN_TIMEOUT = 60 * 1000;/*** 创建HttpClient客户端** @param isHttps* @return*/private static CloseableHttpClient createClient(boolean isHttps){HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();if (isHttps){try{SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy(){// 信任所有public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException{return true;}}).build();SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);httpClientBuilder.setSSLSocketFactory(sslsf);}catch (Exception e){e.printStackTrace();logger.error("创建HTTPS客户端异常");}}return httpClientBuilder.build();}/*** 支持 http、https协议* 调用Get接口* @param url 接口地址* @param isHttps [true:https协议,false:http协议]* @return*/public static String sendGet(String url, boolean isHttps){CloseableHttpClient httpClient = createClient(isHttps);if (url == null || "".equals(url)){logger.error("接口地址为空");return null;}HttpGet request = null;try{request = new HttpGet(url);if (httpClient == null){logger.error("HttpClient实例为空");return null;}setTimeOut(request);CloseableHttpResponse response = httpClient.execute(request);if (response.getStatusLine().getStatusCode() == 200){return EntityUtils.toString(response.getEntity());}}catch (Exception e){logger.error("访问接口失败,接口地址为:" + url);}finally{if (request != null)request.releaseConnection();}return null;}/*** 调用Post接口** @param url 接口地址* @param params 参数* @param type 参数类型,0:键值对,1:json数据* @param isHttps 参数类型 false:http协议,true:https协议* @return*/public static String sendPost(String url, String parameters, int type, boolean isHttps){CloseableHttpClient httpClient = createClient(isHttps);if (url == null || "".equals(url)){logger.error("接口地址为空");return null;}HttpPost request = null;try{request = new HttpPost(url);if (httpClient == null){logger.error("HttpClient实例为空");return null;}setTimeOut(request);StringEntity entity = new StringEntity(parameters, "UTF-8");if (type == Format_KeyValue){// request.addHeader("Content-Type", "application/x-www-form-urlencoded");entity.setContentType("application/x-www-form-urlencoded");}else if (type == Format_Json){// request.addHeader("Content-Type", "application/json");entity.setContentType("application/json");}else{logger.error("不支持的参数格式");return null;}request.setEntity(entity);CloseableHttpResponse response = httpClient.execute(request);if (response.getStatusLine().getStatusCode() == 200){return EntityUtils.toString(response.getEntity());}}catch (Exception e){logger.error("访问接口失败,接口地址为:" + url);throw new RuntimeException(e.getMessage());}finally{if (request != null)request.releaseConnection();}return null;}/*** 调用Post接口,参数为键值对方式** @param url 接口地址* @param params 键值对参数* @param isHttps 参数类型 false:http协议,true:https协议* @return*/public static String sendPostByKeyValue(String url, Mapparams, boolean isHttps) {CloseableHttpClient httpClient = createClient(isHttps);if (url == null || "".equals(url)){logger.error("接口地址为空");return null;}HttpPost request = null;try{request = new HttpPost(url);if (httpClient == null){logger.error("HttpClient实例为空");return null;}setTimeOut(request);Listnvps = new ArrayList (); for (Map.Entryentry : params.entrySet()) {nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));}request.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));CloseableHttpResponse response = httpClient.execute(request);if (response.getStatusLine().getStatusCode() == 200){return EntityUtils.toString(response.getEntity());}}catch (Exception e){logger.error("访问接口失败,接口地址为:" + url);}finally{if (request != null)request.releaseConnection();}return null;}/*** 调用Post接口,参数为JSON格式** @param url 接口地址* @param params json数据* @param isHttps 参数类型 false:http协议,true:https协议* @return*/public static String sendPostByJson(String url, String params,boolean isHttps){return sendPost(url, params, Format_Json, isHttps);}/*** 设置 请求超时* @author ducl* @param methodType void* @date 2020年7月1日上午8:55:44*/private static void setTimeOut(HttpRequestBase methodType){RequestConfig config = RequestConfig.custom().setConnectTimeout(SOCKET_TIMEOUT).setConnectionRequestTimeout(CONN_TIMEOUT).setSocketTimeout(SOCKET_TIMEOUT).build();methodType.setConfig(config);}}
home.js
/** @format */import { ApiConfig } from "../utils/config";export default {wechatPhone: {name: "wechatPhone",method: "POST",desc: "拿到微信手机号码",path: ApiConfig.baseUrl + "/yxyz/wechat/dec/userinfo"}};
index.jsx
import Taro from "@tarojs/taro";import React from "react";import { View, Text, Image, Button } from "@tarojs/components";import { AtList, AtListItem, AtIcon } from "taro-ui";import { getData } from "../../utils/request";import home from "../../api/home";import "./index.scss";import { checkStaticImg } from "../../utils";import { connect } from "react-redux";import { commitUserInfo } from "../../store/actions";const mapStateToProps = state => {return {userInfo: state.my.userInfo};};const mapDispatchToProps = {commitUserInfo};@connect(mapStateToProps, mapDispatchToProps)class My extends React.Component {state = {code: ""};componentDidMount = async () => {const that = this;Taro.login({success: function(res) {console.log(res, "code");if (res.code) {that.setState({ code: res.code });}}});};getUserInfo = res => {console.log(res, "res");if (res.detail && res.detail.userInfo) {this.props.commitUserInfo({ ...this.props.userInfo, ...res.detail.userInfo });}};getPhoneNumber = res => {console.log(res, "res");if (res.detail) {let params = {code: this.state.code,encrypted_data: res.detail.encryptedData,iv: res.detail.iv};console.log(this.userInfo);getData(params, home.wechatPhone).then(res => {console.log(res, "mydata");if (res.data.phoneNumber) {let userInfo = {...this.props.userInfo,phoneNumber: res.data.phoneNumber};this.props.commitUserInfo(userInfo);}});}console.log(res, "res");};render() {let { userInfo } = this.props;return (<View className="my-wrap">{userInfo.nickName ? (<View class="top-wrap"><View class="top-wrap-con"><Image class="logo" src={userInfo.avatarUrl}>Image><View class="top-con"><Text class="title">{userInfo.nickName}Text>{/* <Text class="title">性别:{userInfo.gender === 1 ? "男" : "女"}Text><Text class="title">地址:{userInfo.province}/{userInfo.city}Text> */}{userInfo.phoneNumber ? <Text class="phone">{userInfo.phoneNumber}Text> : null}View><AtIconprefixClassName="iconfont"value="edit-outline"size="16"color={"#999"}className={`iconfont icon-edit-outline`}>AtIcon>View>{/* {userInfo.phoneNumber ? null : (<Button open-type="getPhoneNumber" onGetPhoneNumber={this.getPhoneNumber} class="phone-btn">手机号Button>)} */}View>) : (<View class="top-wrap"><Button open-type="getUserInfo" onGetUserInfo={this.getUserInfo} class="no-login"><Image class="img" src={checkStaticImg("login.png")}>Image><View class="login-label"><Text class="login-label-title">点击登录Text>{userInfo.phoneNumber ? <Text class="phone">{userInfo.phoneNumber}Text> : null}View>Button>View>)}{userInfo.phoneNumber ? null : (<Button open-type="getPhoneNumber" onGetPhoneNumber={this.getPhoneNumber} class="phone-btn">点我获取手机号Button>)}<View class="sep">View><AtList className="list"><Button openType="contact" className="btn-item"><AtListItem title="联系客服" thumb={checkStaticImg("contact.png")} arrow="right" className="list-item" />Button><Button openType="feedback" className="btn-item"><AtListItem title="意见反馈" thumb={checkStaticImg("feedback.png")} arrow="right" className="list-item" />Button>{/* <Button openType="contact" className="btn-item"><Image src={checkStaticImg("contact.png")} className="btn-img">Image><Text className="btn-text">联系客服Text>Button> */}AtList>{/* <View className="btn-wrap"><Button openType="feedback" className="btn-item"><Image src={checkStaticImg("feedback.png")} className="btn-img">Image><Text className="btn-text">意见反馈Text>Button><Button openType="contact" className="btn-item"><Image src={checkStaticImg("contact.png")} className="btn-img">Image><Text className="btn-text">联系客服Text>Button>View> */}View>);}}export default My;
request.js
/** @format */// axios 默认配置export const ApiConfig = {baseUrl: "http://XXX.XXX.XXX.XXX:8000/"};
推荐案例
温暖提示

请长按识别二维码
想学习更多的java功能案例请关注
Java项目开发

如果你觉得这个案例以及我们的分享思路不错,对你有帮助,请分享给身边更多需要学习的朋友。别忘了《留言+点在看》给作者一个鼓励哦!
评论

