0


前端uniapp+后端springboot 详细教程《实现微信小程序授权登录》(附完整前后端项目demo)

实现微信小程序授权登录

微信小程序官方登录流程图:
在这里插入图片描述
参考微信小程序登录官网文档

1、前端技术栈

1.1、uniapp

使用uniapp构建一套代码多端使用的前端框架项目

1.2、前端封装工具
  • dateUtil.js: 功能: 1. 时间日期格式化 2. 传入日期是否和当前日期的比较 完整代码:// 判断传入日期是否和当前日期比较 constjudgeDate=(toDate)=>{returnnewDate().getTime()-newDate(toDate).getTime();}vartimeFormat=function(msTime){let time =newDate(msTime);let yy = time.getFullYear();letMM= time.getMonth()+1;let dd = time.getDate();let hh = time.getHours()<10?"0"+ time.getHours(): time.getHours();let min = time.getMinutes()<10?"0"+ time.getMinutes(): time.getMinutes();let sec = time.getSeconds()<10?"0"+ time.getSeconds(): time.getSeconds();return yy +"-"+MM+"-"+ dd +" "+ hh +":"+ min +":"+ sec;}export{timeFormat,judgeDate}
  • requestUtil.js: 功能: 1. 定义公共的url 2. 后端请求工具封装 完整代码:// 同时发送异步代码的次数let ajaxTimes =0;// 定义公共的urlconst baseUrl ="http://localhost:8866";/** * 返回baseUrl */exportconstgetBaseUrl=()=>{return baseUrl;}/** * 后端请求工具类 * @param {*} params 请求参数 */exportconstrequestUtil=(params)=>{let header ={...params.header };// 拼接header 带上token header["token"]= uni.getStorageSync("token"); ajaxTimes++;// 显示加载中 效果 wx.showLoading({ title:"加载中", mask:true});var start =newDate().getTime();// 模拟网络延迟加载while(true)if(newDate().getTime()- start >1000*1)break;returnnewPromise((resolve, reject)=>{ wx.request({...params, header: header, url: baseUrl + params.url,success:(result)=>{resolve(result.data);},fail:(err)=>{ uni.showToast({ icon:'error', title:'连接服务器失败', duration:3000})reject(err);},complete:()=>{ ajaxTimes--;if(ajaxTimes ===0){// 关闭正在等待的图标 wx.hideLoading();}}});})}
  • stringUtil.js: 功能: 1. 判断字符串是否为空 完整代码://判断字符串是否为空exportconstisEmpty=(str)=>{if(str ===''|| str.trim().length ===0){returntrue}else{returnfalse;}}
1.3、Hbuilderx构建uniapp项目

在这里插入图片描述
项目结构:
在这里插入图片描述

app.vue中,写两个方法:

  1. 在onLaunch生命周期函数中调用wx.login()获取code(前提是在微信开发者工具中登录微信账号,而且在uniapp中设置微信小程序AppId),code的作用是后端接受到code,通过code参数向微信后台发送请求,它是实现微信临时登录的url中的一个非常重要的参数。
  2. 三个重要参数
  • appid:应用ID
  • secret:应用密钥
  • js_code:前台传给我们的code
  1. wxlogin方法 携带code参数发送请求给后端来获取token和openid
<script>import{
    requestUtil
  } from "./utils/requestUtil.js"
  export default{
    onLaunch:function(){
      console.log('App Launch')
      wx.login({
        timeout:5000,
        success:(res)=>{
          console.log(res)this.wxlogin(res.code);}});},
    onShow:function(){
      console.log('App Show')},
    onHide:function(){
      console.log('App Hide')},
    methods:{/**
       * 请求后端获取用户token
       * @param {} code 
       */
      async wxlogin(code){
        console.log("code="+ code)// 发送请求 获取用户的tokenconst result = await requestUtil({
          url:"/user/wxlogin",
          data:{
            code: code
          },
          method:"post"});
        console.log("token="+ result.token);
        console.log("openid="+ result.openid);if(result.code ==0){
          console.log("登录成功")
          uni.setStorageSync("token", result.token);
          uni.setStorageSync("openid", result.openid);}else{
          console.log("登录失败,报错信息:"+ result.msg);
          uni.showToast({
            icon:'error',
            title: result.msg,
            duration:3000})}}}}</script><style>/*每个页面公共css */</style>

2、后端技术栈

  • springboot后端技术框架
  • mybatis-plus数据持久层框架
2.1、创建springboot后端项目

利用idea工具,使用spring initializr初始化创建一个空的springboot项目

springboot版本选择2.3.2.RELEASE。

  1. 修改pom.xml
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!-- 连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version></dependency><!-- mybatis-plus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.3.2</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.40</version></dependency><!--JWT--><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.2.0</version></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.5</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- spring boot redis 缓存引入 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- lettuce pool 缓存连接池 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency><!-- hutool工具类--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.3.3</version></dependency><!-- 验证码依赖--><dependency><groupId>com.github.axet</groupId><artifactId>kaptcha</artifactId><version>0.0.9</version></dependency><!-- 添加Httpclient支持 --><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.2</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.3.2.RELEASE</version></plugin></plugins></build>
  1. 创建application.yml
server:
  port:8866
  servlet:
    context-path:/

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db-wxlogin?serverTimezone=Asia/Shanghai
    username: root
    password:123456

mybatis-plus:
  global-config:
    db-config:
      id-type: auto
  configuration:
    map-underscore-to-camel-case:true
    auto-mapping-behavior: full
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath:mapper/*.xml

weixin:
  jscode2sessionUrl: https://api.weixin.qq.com/sns/jscode2session
  appid: wxa4aa78831ea93858  #修改自己的微信小程序 appId
  secret: a2efb3b611d96b2dee615b7a4dee451a   #修改自己的微信小程序 appSecret
2.2、数据库准备

创建名称db-wxlogin的数据库

创建t_wxuserinfo数据表
CREATETABLE`t_wxuserinfo`(`id` int NOTNULLAUTO_INCREMENTCOMMENT'用户编号',`openid`varchar(30)DEFAULTNULLCOMMENT'用户唯一标识',`nick_name`varchar(50)DEFAULTNULLCOMMENT'用户昵称',`avatar_url`varchar(200)DEFAULTNULLCOMMENT'用户头像图片的 URL',`register_date` datetime DEFAULTNULLCOMMENT'注册日期',`last_login_date` datetime DEFAULTNULLCOMMENT'最后登录日期',`status`char(1)DEFAULT'1'COMMENT'状态 0 可用 1 封禁',PRIMARYKEY(`id`))ENGINE=InnoDB AUTO_INCREMENT=2DEFAULTCHARSET=utf8;
2.3、创建实体类
  • WxUserInfo类 对应数据库表t_wxuserinfo
packagecom.tigerhhzz.springbootvote.entity;importcom.baomidou.mybatisplus.annotation.TableField;importcom.baomidou.mybatisplus.annotation.TableName;importcom.fasterxml.jackson.databind.annotation.JsonSerialize;importlombok.Data;importjava.io.Serializable;importjava.util.Date;/**
 * 微信用户信息实体
 *
 * @author tigerhhzz
 * @date 2023/5/17 15:34
 */@TableName("t_wxUserInfo")@DatapublicclassWxUserInfoimplementsSerializable{privateInteger id;// 用户编号privateString openid;// 用户唯一标识privateString nickName="微信用户";// 用户昵称privateString avatarUrl="default.png";// 用户头像图片的 URL@JsonSerialize(using=CustomDateTimeSerializer.class)privateDate registerDate;// 注册日期@JsonSerialize(using=CustomDateTimeSerializer.class)privateDate lastLoginDate;// 最后登录日期privateString status="0";// 用户状态 状态 0 可用 1 封禁//查询时,则不返回该字段的值    设置该字段在数据库表中不存在@TableField(select =false,exist =false)privateString code;// 微信用户code 前端传来的}
  • 页面响应实体类
packagecom.tigerhhzz.springbootvote.entity;importjava.util.HashMap;importjava.util.Map;/**
 * 页面响应entity
 *
 * @author tigerhhzz
 * @date 2023/5/17 15:34
 */publicclassRextendsHashMap<String,Object>{privatestaticfinallong serialVersionUID =1L;publicR(){put("code",0);}publicstaticRerror(){returnerror(500,"未知异常,请联系管理员");}publicstaticRerror(String msg){returnerror(500, msg);}publicstaticRerror(int code,String msg){R r =newR();
        r.put("code", code);
        r.put("msg", msg);return r;}publicstaticRok(String msg){R r =newR();
        r.put("msg", msg);return r;}publicstaticRok(Map<String,Object> map){R r =newR();
        r.putAll(map);return r;}publicstaticRok(){returnnewR();}@OverridepublicRput(String key,Object value){super.put(key, value);returnthis;}}
  • jwt验证信息
packagecom.tigerhhzz.springbootvote.entity;importio.jsonwebtoken.Claims;/**
 * jwt验证信息
 *
 * @author tigerhhzz
 * @date 2023/5/17 17:05
 */publicclassCheckResult{privateint errCode;privateboolean success;privateClaims claims;publicintgetErrCode(){return errCode;}publicvoidsetErrCode(int errCode){this.errCode = errCode;}publicbooleanisSuccess(){return success;}publicvoidsetSuccess(boolean success){this.success = success;}publicClaimsgetClaims(){return claims;}publicvoidsetClaims(Claims claims){this.claims = claims;}}
  • 微信小程序配置文件
packagecom.tigerhhzz.springbootvote.properties;importlombok.Data;importorg.springframework.boot.context.properties.ConfigurationProperties;importorg.springframework.stereotype.Component;/**
 * 微信小程序配置文件
 *
 * @author tigerhhzz
 * @date 2023/5/17 16:55
 */@Component@ConfigurationProperties(prefix ="weixin")@DatapublicclassWeixinProperties{privateString jscode2sessionUrl;// 登录凭证校验请求地址privateString appid;// 小程序 appIdprivateString secret;// 小程序 appSecret}
2.4、后端工具类
  • 日期工具类 DateUtil
packagecom.tigerhhzz.springbootvote.util;importjava.text.SimpleDateFormat;importjava.util.Date;/**
 * 日期工具类
 *
 * @author tigerhhzz
 * @date 2023/5/17 15:34
 */publicclassDateUtil{/**
     * 日期对象转字符串
     * @param date
     * @param format
     * @return
     */publicstaticStringformatDate(Date date,String format){String result="";SimpleDateFormat sdf=newSimpleDateFormat(format);if(date!=null){
            result=sdf.format(date);}return result;}/**
     * 字符串转日期对象
     * @param str
     * @param format
     * @return
     * @throws Exception
     */publicstaticDateformatString(String str,String format)throwsException{if(StringUtil.isEmpty(str)){returnnull;}SimpleDateFormat sdf=newSimpleDateFormat(format);return sdf.parse(str);}publicstaticStringgetCurrentDateStr(){Date date=newDate();SimpleDateFormat sdf=newSimpleDateFormat("yyyyMMddhhmmssSSSSSSSSS");return sdf.format(date);}publicstaticStringgetCurrentDatePath()throwsException{Date date=newDate();SimpleDateFormat sdf=newSimpleDateFormat("yyyy/MM/dd/");return sdf.format(date);}publicstaticvoidmain(String[] args){try{System.out.println(getCurrentDateStr());}catch(Exception e){// TODO Auto-generated catch block
            e.printStackTrace();}}}
  • httpClient 工具类
packagecom.tigerhhzz.springbootvote.util;importorg.apache.http.HttpEntity;importorg.apache.http.HttpResponse;importorg.apache.http.NameValuePair;importorg.apache.http.client.ClientProtocolException;importorg.apache.http.client.HttpClient;importorg.apache.http.client.config.RequestConfig;importorg.apache.http.client.entity.UrlEncodedFormEntity;importorg.apache.http.client.methods.CloseableHttpResponse;importorg.apache.http.client.methods.HttpGet;importorg.apache.http.client.methods.HttpPost;importorg.apache.http.conn.ssl.DefaultHostnameVerifier;importorg.apache.http.conn.util.PublicSuffixMatcher;importorg.apache.http.conn.util.PublicSuffixMatcherLoader;importorg.apache.http.entity.StringEntity;importorg.apache.http.impl.client.CloseableHttpClient;importorg.apache.http.impl.client.HttpClients;importorg.apache.http.message.BasicNameValuePair;importorg.apache.http.util.EntityUtils;importorg.springframework.stereotype.Component;importjava.io.*;importjava.net.URL;importjava.util.ArrayList;importjava.util.List;importjava.util.Map;/**
 * httpClient 工具类
 *
 * @author tigerhhzz
 * @date 2023/5/17 15:34
 */@ComponentpublicclassHttpClientUtil{/**
     * 默认参数设置
     * setConnectTimeout:设置连接超时时间,单位毫秒。
     * setConnectionRequestTimeout:设置从connect Manager获取Connection 超时时间,单位毫秒。
     * setSocketTimeout:请求获取数据的超时时间,单位毫秒。访问一个接口,多少时间内无法返回数据,就直接放弃此次调用。 暂时定义15分钟
     */privateRequestConfig requestConfig =RequestConfig.custom().setSocketTimeout(600000).setConnectTimeout(600000).setConnectionRequestTimeout(600000).build();/**
     * 静态内部类---作用:单例产生类的实例
     * @author Administrator
     *
     */privatestaticclassLazyHolder{privatestaticfinalHttpClientUtil INSTANCE =newHttpClientUtil();}privateHttpClientUtil(){}publicstaticHttpClientUtilgetInstance(){returnLazyHolder.INSTANCE;}/**
     * 发送 post请求
     * @param httpUrl 地址
     */publicStringsendHttpPost(String httpUrl){HttpPost httpPost =newHttpPost(httpUrl);// 创建httpPost  returnsendHttpPost(httpPost);}/**
     * 发送 post请求
     * @param httpUrl 地址
     * @param params 参数(格式:key1=value1&key2=value2)
     */publicStringsendHttpPost(String httpUrl,String params){HttpPost httpPost =newHttpPost(httpUrl);// 创建httpPost  try{//设置参数StringEntity stringEntity =newStringEntity(params,"UTF-8");
            stringEntity.setContentType("application/x-www-form-urlencoded");
            httpPost.setEntity(stringEntity);}catch(Exception e){
            e.printStackTrace();}returnsendHttpPost(httpPost);}/**
     * 发送 post请求
     * @param httpUrl 地址
     * @param maps 参数
     */publicStringsendHttpPost(String httpUrl,Map<String,String> maps){HttpPost httpPost =newHttpPost(httpUrl);// 创建httpPost  // 创建参数队列  List<NameValuePair> nameValuePairs =newArrayList<NameValuePair>();for(String key : maps.keySet()){
            nameValuePairs.add(newBasicNameValuePair(key, maps.get(key)));}try{
            httpPost.setEntity(newUrlEncodedFormEntity(nameValuePairs,"UTF-8"));}catch(Exception e){
            e.printStackTrace();}returnsendHttpPost(httpPost);}/**
     * 发送Post请求
     * @param httpPost
     * @return
     */privateStringsendHttpPost(HttpPost httpPost){CloseableHttpClient httpClient =null;CloseableHttpResponse response =null;HttpEntity entity =null;String responseContent =null;try{// 创建默认的httpClient实例
            httpClient =HttpClients.createDefault();
            httpPost.setConfig(requestConfig);// 执行请求long execStart =System.currentTimeMillis();
            response = httpClient.execute(httpPost);long execEnd =System.currentTimeMillis();System.out.println("=================执行post请求耗时:"+(execEnd-execStart)+"ms");long getStart =System.currentTimeMillis();
            entity = response.getEntity();
            responseContent =EntityUtils.toString(entity,"UTF-8");long getEnd =System.currentTimeMillis();System.out.println("=================获取响应结果耗时:"+(getEnd-getStart)+"ms");}catch(Exception e){
            e.printStackTrace();}finally{try{// 关闭连接,释放资源if(response !=null){
                    response.close();}if(httpClient !=null){
                    httpClient.close();}}catch(IOException e){
                e.printStackTrace();}}return responseContent;}/**
     * 发送 get请求
     * @param httpUrl
     */publicStringsendHttpGet(String httpUrl){HttpGet httpGet =newHttpGet(httpUrl);// 创建get请求returnsendHttpGet(httpGet);}/**
     * 发送 get请求Https
     * @param httpUrl
     */publicStringsendHttpsGet(String httpUrl){HttpGet httpGet =newHttpGet(httpUrl);// 创建get请求returnsendHttpsGet(httpGet);}/**
     * 发送Get请求
     * @param httpGet
     * @return
     */privateStringsendHttpGet(HttpGet httpGet){CloseableHttpClient httpClient =null;CloseableHttpResponse response =null;HttpEntity entity =null;String responseContent =null;try{// 创建默认的httpClient实例.

            
            httpClient =HttpClients.createDefault();

            httpGet.setConfig(requestConfig);// 执行请求
            response = httpClient.execute(httpGet);
            entity = response.getEntity();
            responseContent =EntityUtils.toString(entity,"UTF-8");}catch(Exception e){
            e.printStackTrace();}finally{try{// 关闭连接,释放资源if(response !=null){
                    response.close();}if(httpClient !=null){
                    httpClient.close();}}catch(IOException e){
                e.printStackTrace();}}return responseContent;}/**
     * 发送Get请求Https
     * @param httpGet
     * @return
     */privateStringsendHttpsGet(HttpGet httpGet){CloseableHttpClient httpClient =null;CloseableHttpResponse response =null;HttpEntity entity =null;String responseContent =null;try{// 创建默认的httpClient实例.PublicSuffixMatcher publicSuffixMatcher =PublicSuffixMatcherLoader.load(newURL(httpGet.getURI().toString()));DefaultHostnameVerifier hostnameVerifier =newDefaultHostnameVerifier(publicSuffixMatcher);
            httpClient =HttpClients.custom().setSSLHostnameVerifier(hostnameVerifier).build();
            httpGet.setConfig(requestConfig);// 执行请求
            response = httpClient.execute(httpGet);
            entity = response.getEntity();
            responseContent =EntityUtils.toString(entity,"UTF-8");}catch(Exception e){
            e.printStackTrace();}finally{try{// 关闭连接,释放资源if(response !=null){
                    response.close();}if(httpClient !=null){
                    httpClient.close();}}catch(IOException e){
                e.printStackTrace();}}return responseContent;}/**
     * 发送xml数据
     * @param url
     * @param xmlData
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     */publicstaticHttpResponsesendXMLDataByPost(String url,String xmlData)throwsClientProtocolException,IOException{HttpClient httpClient =HttpClients.createDefault();HttpPost httppost =newHttpPost(url);StringEntity entity =newStringEntity(xmlData);
        httppost.setEntity(entity);
        httppost.setHeader("Content-Type","text/xml;charset=UTF-8");HttpResponse response = httpClient.execute(httppost);return response;}/**
     * 获得响应HTTP实体内容
     *
     * @param response
     * @return
     * @throws IOException
     * @throws UnsupportedEncodingException
     */publicstaticStringgetHttpEntityContent(HttpResponse response)throwsIOException,UnsupportedEncodingException{HttpEntity entity = response.getEntity();if(entity !=null){InputStream is = entity.getContent();BufferedReader br =newBufferedReader(newInputStreamReader(is,"UTF-8"));String line = br.readLine();StringBuilder sb =newStringBuilder();while(line !=null){
                sb.append(line +"\n");
                line = br.readLine();}return sb.toString();}return"";}}
  • jwt加密和解密的工具类
packagecom.tigerhhzz.springbootvote.util;importcom.tigerhhzz.springbootvote.constant.JwtConstant;importcom.tigerhhzz.springbootvote.entity.CheckResult;importio.jsonwebtoken.*;importorg.bouncycastle.util.encoders.Base64;importjavax.crypto.SecretKey;importjavax.crypto.spec.SecretKeySpec;importjava.util.Date;/**
 * jwt加密和解密的工具类
 *
 * @author tigerhhzz
 * @date 2023/5/17 15:34
 */publicclassJwtUtils{/**
     * 签发JWT
     * @param id
     * @param subject 可以是JSON数据 尽可能少
     * @param ttlMillis
     * @return
     */publicstaticStringcreateJWT(String id,String subject,long ttlMillis){SignatureAlgorithm signatureAlgorithm =SignatureAlgorithm.HS256;long nowMillis =System.currentTimeMillis();Date now =newDate(nowMillis);SecretKey secretKey =generalKey();JwtBuilder builder =Jwts.builder().setId(id).setSubject(subject)// 主题.setIssuer("tigerhhzz")// 签发者.setIssuedAt(now)// 签发时间.signWith(signatureAlgorithm, secretKey);// 签名算法以及密匙if(ttlMillis >=0){long expMillis = nowMillis + ttlMillis;Date expDate =newDate(expMillis);
            builder.setExpiration(expDate);// 过期时间}return builder.compact();}/**
     * 生成jwt token
     * @param username
     * @return
     */publicstaticStringgenJwtToken(String username){returncreateJWT(username,username,60*60*1000);}/**
     * 验证JWT
     * @param jwtStr
     * @return
     */publicstaticCheckResultvalidateJWT(String jwtStr){CheckResult checkResult =newCheckResult();Claims claims =null;try{
            claims =parseJWT(jwtStr);
            checkResult.setSuccess(true);
            checkResult.setClaims(claims);}catch(ExpiredJwtException e){
            checkResult.setErrCode(JwtConstant.JWT_ERRCODE_EXPIRE);
            checkResult.setSuccess(false);}catch(SignatureException e){
            checkResult.setErrCode(JwtConstant.JWT_ERRCODE_FAIL);
            checkResult.setSuccess(false);}catch(Exception e){
            checkResult.setErrCode(JwtConstant.JWT_ERRCODE_FAIL);
            checkResult.setSuccess(false);}return checkResult;}/**
     * 生成加密Key
     * @return
     */publicstaticSecretKeygeneralKey(){byte[] encodedKey =Base64.decode(JwtConstant.JWT_SECERT);SecretKey key =newSecretKeySpec(encodedKey,0, encodedKey.length,"AES");return key;}/**
     * 解析JWT字符串
     * @param jwt
     * @return
     * @throws Exception
     */publicstaticClaimsparseJWT(String jwt){SecretKey secretKey =generalKey();returnJwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();}publicstaticvoidmain(String[] args)throwsInterruptedException{//小明失效 10sString sc =createJWT("1","小明",60*60*1000);System.out.println(sc);System.out.println(validateJWT(sc).getErrCode());System.out.println(validateJWT(sc).getClaims().getId());System.out.println(validateJWT(sc).getClaims().getSubject());//Thread.sleep(3000);System.out.println(validateJWT(sc).getClaims());Claims claims =validateJWT(sc).getClaims();String sc2 =createJWT(claims.getId(),claims.getSubject(),JwtConstant.JWT_TTL);System.out.println(sc2);}}
  • 字符串工具类
packagecom.tigerhhzz.springbootvote.util;importjava.util.ArrayList;importjava.util.List;importjava.util.Random;/**
 * 字符串工具类
 * @author 
 *
 */publicclassStringUtil{/**
     * 判断是否是空
     * @param str
     * @return
     */publicstaticbooleanisEmpty(String str){if(str==null||"".equals(str.trim())){returntrue;}else{returnfalse;}}/**
     * 判断是否不是空
     * @param str
     * @return
     */publicstaticbooleanisNotEmpty(String str){if((str!=null)&&!"".equals(str.trim())){returntrue;}else{returnfalse;}}/**
     * 格式化模糊查询
     * @param str
     * @return
     */publicstaticStringformatLike(String str){if(isNotEmpty(str)){return"%"+str+"%";}else{returnnull;}}/**
     * 过滤掉集合里的空格
     * @param list
     * @return
     */publicstaticList<String>filterWhite(List<String> list){List<String> resultList=newArrayList<String>();for(String l:list){if(isNotEmpty(l)){
                resultList.add(l);}}return resultList;}/**
     * 去除html标签
     */publicstaticStringstripHtml(String content){// <p>段落替换为换行 
        content = content.replaceAll("<p .*?>","\r\n");// <br><br/>替换为换行 
        content = content.replaceAll("<br\\s*/?>","\r\n");// 去掉其它的<>之间的东西 
        content = content.replaceAll("\\<.*?>","");// 去掉空格 
        content = content.replaceAll(" ","");return content;}/**
     * 生成六位随机数
     * @return
     */publicstaticStringgenSixRandomNum(){Random random =newRandom();String result="";for(int i=0;i<6;i++){
            result+=random.nextInt(10);}return result;}/**
     * 生成由[A-Z,0-9]生成的随机字符串
     * @param length  欲生成的字符串长度
     * @return
     */publicstaticStringgetRandomString(int length){Random random =newRandom();StringBuffer sb =newStringBuffer();for(int i =0; i < length;++i){int number = random.nextInt(2);long result =0;switch(number){case0:
                    result =Math.round(Math.random()*25+65);
                    sb.append(String.valueOf((char)result));break;case1:

                    sb.append(String.valueOf(newRandom().nextInt(10)));break;}}return sb.toString();}}
2.5、mapper和service接口

微信用户mapper —WxUserInfoMapper

packagecom.tigerhhzz.springbootvote.mapper;importcom.baomidou.mybatisplus.core.mapper.BaseMapper;importcom.tigerhhzz.springbootvote.entity.WxUserInfo;importorg.springframework.stereotype.Repository;/**
 * 微信用户mapper
 *
 * @author tigerhhzz
 * @date 2023/5/17 15:26
 */@RepositorypublicinterfaceWxUserInfoMapperextendsBaseMapper<WxUserInfo>{}

微信用户Service接口 —WxUserInfoService

packagecom.tigerhhzz.springbootvote.service;importcom.baomidou.mybatisplus.extension.service.IService;importcom.tigerhhzz.springbootvote.entity.WxUserInfo;/**
 * 微信用户Service接口
 *
 * @author tigerhhzz
 * @date 2023/5/17 15:34
 */publicinterfaceWxUserInfoServiceextendsIService<WxUserInfo>{}
2.5、Service实现类

WxUserInfoServiceImpl---- 实现WxUserInfoService 接口,并继承ServiceImpl实现类的泛型WxUserInfoMapper和WxUserInfo。

packagecom.tigerhhzz.springbootvote.service.impl;importcom.baomidou.mybatisplus.extension.service.impl.ServiceImpl;importcom.tigerhhzz.springbootvote.entity.WxUserInfo;importcom.tigerhhzz.springbootvote.mapper.WxUserInfoMapper;importcom.tigerhhzz.springbootvote.service.WxUserInfoService;importorg.springframework.stereotype.Service;/**
 * 微信用户Service实现类
 *
 * @author tigerhhzz
 * @date 2023/5/17 15:34
 */@Service//("wxUserInfoService")publicclassWxUserInfoServiceImplextendsServiceImpl<WxUserInfoMapper,WxUserInfo>implementsWxUserInfoService{//@Autowired//private WxUserInfoMapper wxUserInfoMapper;}
2.6、微信用户的控制层Controller

两个控制层请求接口

  1. /user/wxlogin

功能: 通过前端发送请求携带的参数code以及后端配置文件中的微信小程序appid和微信小程序密钥,后端拼接url向微信后台发送请求。

String jscode2sessionUrl=weixinProperties.getJscode2sessionUrl()+"?appid="+weixinProperties.getAppid()+"&secret="+weixinProperties.getSecret()+"&js_code="+wxUserInfo.getCode()+"&grant_type=authorization_code";// https://api.weixin.qq.com/sns/jscode2session?appid=wxa4de78832ea93858&secret=a2efb3b602d96b2dee615b7a4dee451a&js_code=0b1JwPkl2xqHkb4VEjml2vVdua3JwPkq&grant_type=authorization_code
//后端向微信后台送发请求 获取openidString result = httpClientUtil.sendHttpGet(jscode2sessionUrl);System.out.println(result);//结果:{"session_key":"TPTXzC9MOe1owBJ8zrSWTw==","openid":"o2yqx5PBEW-ezFHA24ASqP0Lk1M0"}

通过拿到的openid,去数据库查询对应用户信息,如果没有openid的用户,进行新增操作;
如果存在openid的用户,进行更新操作。

最后利用jwt工具类生成token,返回前端

// 利用jwt生成token返回到前端String token =JwtUtils.createJWT(openid, wxUserInfo.getNickName(),JwtConstant.JWT_TTL);
Map<String,Object> resultMap=newHashMap<>();
  resultMap.put("token",token);
  resultMap.put("openid",openid);returnR.ok(resultMap);
  1. /user/getUserInfo

功能: 通过前端发送请求,请求头中携带token参数,后端接受到token,然后进行token验证,拿到openid,通过openid去数据库中查询用户信息,并返回前端

//token验证Claims claims =JwtUtils.validateJWT(token).getClaims();

获取当前微信登录用户信息:
在这里插入图片描述


WeixinUserController 完整代码:

packagecom.tigerhhzz.springbootvote.controller;importcom.alibaba.fastjson.JSON;importcom.alibaba.fastjson.JSONObject;importcom.baomidou.mybatisplus.core.conditions.query.QueryWrapper;importcom.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;importcom.tigerhhzz.springbootvote.constant.JwtConstant;importcom.tigerhhzz.springbootvote.entity.R;importcom.tigerhhzz.springbootvote.entity.WxUserInfo;importcom.tigerhhzz.springbootvote.properties.WeixinProperties;importcom.tigerhhzz.springbootvote.service.WxUserInfoService;importcom.tigerhhzz.springbootvote.util.DateUtil;importcom.tigerhhzz.springbootvote.util.HttpClientUtil;importcom.tigerhhzz.springbootvote.util.JwtUtils;importcom.tigerhhzz.springbootvote.util.StringUtil;importio.jsonwebtoken.Claims;importorg.apache.commons.io.FileUtils;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.web.bind.annotation.RequestBody;importorg.springframework.web.bind.annotation.RequestHeader;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importorg.springframework.web.multipart.MultipartFile;importjava.io.File;importjava.util.Date;importjava.util.HashMap;importjava.util.List;importjava.util.Map;/**
 * 微信用户Controller
 *
 * @author tigerhhzz
 * @date 2023/5/17 15:34
 */@RequestMapping("/user")@RestControllerpublicclassWeixinUserController{@AutowiredprivateWxUserInfoService wxUserInfoService;@AutowiredprivateWeixinProperties weixinProperties;@AutowiredprivateHttpClientUtil httpClientUtil;/**
     * 微信用户登录
     * @return
     */@RequestMapping("/wxlogin")publicRwxLogin(@RequestBodyWxUserInfo wxUserInfo){//拼接后端发送请求的URL 例如 https://api.weixin.qq.com/sns/jscode2session?appid=wxa4de78832ea93858&secret=a2efb3b602d96b2dee615b7a4dee451a&js_code=0b1JwPkl2xqHkb4VEjml2vVdua3JwPkq&grant_type=authorization_codeString jscode2sessionUrl=weixinProperties.getJscode2sessionUrl()+"?appid="+weixinProperties.getAppid()+"&secret="+weixinProperties.getSecret()+"&js_code="+wxUserInfo.getCode()+"&grant_type=authorization_code";System.out.println(jscode2sessionUrl);//后端向微信后台送发请求 获取openidString result = httpClientUtil.sendHttpGet(jscode2sessionUrl);System.out.println(result);//结果:{"session_key":"TPTXzC9MOe1owBJ8zrSWTw==","openid":"o2yqx5PBEW-ezFHA24ASqP0Lk1M0"}//JSONObject jsonObject= JSON.parseObject(result);//转换成objectString openid = jsonObject.get("openid").toString();//获取object中openid字段的值;System.out.println(openid);// 插入用户到数据库  假如说 用户不存在 我们插入用户  如果用户存在 我们更新用户WxUserInfo resultWxUserInfo = wxUserInfoService.getOne(newQueryWrapper<WxUserInfo>().eq("openid", openid));if(resultWxUserInfo==null){System.out.println("不存在 插入用户");
            wxUserInfo.setOpenid(openid);
            wxUserInfo.setRegisterDate(newDate());
            wxUserInfo.setLastLoginDate(newDate());
            wxUserInfoService.save(wxUserInfo);}else{System.out.println("存在 更新用户");// resultWxUserInfo.setNickName(wxUserInfo.getNickName());// resultWxUserInfo.setAvatarUrl(wxUserInfo.getAvatarUrl());
            resultWxUserInfo.setLastLoginDate(newDate());
            wxUserInfoService.updateById(resultWxUserInfo);}if(resultWxUserInfo!=null&& resultWxUserInfo.getStatus().equals("1")){// 被禁用returnR.error(400,"用户被禁用,具体请联系管理员!");}else{// 利用jwt生成token返回到前端String token =JwtUtils.createJWT(openid, wxUserInfo.getNickName(),JwtConstant.JWT_TTL);Map<String,Object> resultMap=newHashMap<>();
            resultMap.put("token",token);
            resultMap.put("openid",openid);returnR.ok(resultMap);}}/**
     * 获取当前用户信息
     * @return
     */@RequestMapping("/getUserInfo")publicRgetUserInfo(@RequestHeaderString token){System.out.println("/getUserInfo----token="+token);Claims claims =JwtUtils.validateJWT(token).getClaims();System.out.println("openid="+claims.getId());WxUserInfo currentUser = wxUserInfoService.getOne(newQueryWrapper<WxUserInfo>().eq("openid", claims.getId()));Map<String,Object> map=newHashMap<>();
        map.put("currentUser",currentUser);returnR.ok(map);}}

前端源码下载地址 https://download.csdn.net/download/weixin_43025151/87803315

后端源码下载地址:https://download.csdn.net/download/weixin_43025151/87803318


本文转载自: https://blog.csdn.net/weixin_43025151/article/details/130779857
版权归原作者 hhzz 所有, 如有侵权,请联系我们删除。

“前端uniapp+后端springboot 详细教程《实现微信小程序授权登录》(附完整前后端项目demo)”的评论:

还没有评论