微信公众号登录

news2025/2/2 19:04:27

整个流程,
1.前端调用授权url 接口(创建一个重定向的请求方法,访问自动回调方法wechat.mp.callbackUrl的地址)。
2.微信自动回调方法里判断该用户是需要注册还是直接登录(如果直接登录就返回token)
是注册还是登录返回到配置文件中的 wechat.mp.url前端中转地址后面拼接上参数用来标识 是注册还是登录,比如是注册就在地址后拼接 action=register 如果是直接登录就返回action=jump后面在拼接上&token=值 &openId=值 &accountId=值,用重定向的方式

微信公众号后台配置地址:微信公众平台 (微信扫码就能登录进来)

image.png

 

1.配置文件
1.1 properties文件
 

# 微信公众平台授权
wechat.mp.clientId=wxb90a4c***f2de80
wechat.mp.secret=8e4380916bac1***d11a30e0cb7af68
//该回调地址需要在公众号后台配置
wechat.mp.callbackUrl=https://gw-dev.公司域名部分.com.cn/training/h5/social/callback
//这个是前端 中转页, (验证是否注册还是登录重定向到该页面,前端根据参数判断)
wechat.mp.url=https://gw-dev.公司域名部分.com.cn/training/doc.html#/home

1.2 java代码配置文件
1.2.1 WeChatMpProperty.class(自动注入配置)
 

package com.公司域名部分.training.config;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.List;

/**
 * @author 
 * @description
 * @date 2022/12/1
 */
@Data
@ConfigurationProperties(prefix = "wechat.mp")
public class WeChatMpProperty {

    private String clientId;

    private String secret;

    private String callbackUrl;

    private String url;

    private String token;

    private String aesKey;

    @Value("${useRedis:true}")
    private Boolean useRedis;

    private List<Msg> msgs;

    @Data
    public static class Msg {
        private String title;
        private String templateId;
    }
}

1.2.2 WxMpConfiguration.class(公众号配置类)
 

package com.公司简写.training.config;

import com.公司简写.training.common.constants.RedisConstant;
import lombok.AllArgsConstructor;
import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;

/**
 * @author 
 * @description
 * @date 2023/2/28
 */
@AllArgsConstructor
@Configuration
@EnableConfigurationProperties(WeChatMpProperty.class)
public class WxMpConfiguration {
    private final WeChatMpProperty weChatMpProperty;
    private final StringRedisTemplate redisTemplate;

    @Bean
    public WxMpService wxMpService() {
        WxMpService service = new WxMpServiceImpl();
        WxMpDefaultConfigImpl configStorage;
        if(weChatMpProperty.getUseRedis()) {
            configStorage = new WxMpRedisConfigImpl(new RedisTemplateWxRedisOps(redisTemplate), RedisConstant.REDIS_MP);
        }else {
            configStorage = new WxMpDefaultConfigImpl();
        }
        configStorage.setAppId(weChatMpProperty.getClientId());
        configStorage.setSecret(weChatMpProperty.getSecret());

        service.setWxMpConfigStorage(configStorage);
        return service;
    }

}

2. 生成授权url及微信回调方法
2.1 controller代码
 

package com.公司简写.training.controller.wechat.auth;

import com.公司简写.boot.controller.BaseController;
import com.公司简写.training.service.SocialUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import me.zhyd.oauth.model.AuthCallback;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;

/**
 * 公众号
 * @author 
 * @date 2022/12/1
 */
@Api(tags = "h5-公众号")
@RestController("h5SocialController")
@RequiredArgsConstructor
@RequestMapping("/h5/social")
public class SocialController extends BaseController {

    private final SocialUserService socialUserService;

    @GetMapping("/render")
    @ApiOperation(value = "生成授权url", notes = "生成授权url")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "part", value = "前端跳转到页面的标识", required = false, dataType = "String"),
            @ApiImplicitParam(name = "type", value = "1.老师 2.家长", required = true, dataType = "Integer")
    })
    public void renderAuth(@RequestParam(required = false) final String part,
                           @RequestParam final Integer type,
                           HttpServletResponse response) {
        socialUserService.renderAuth(part,type, response);
    }

/**
* 该方法是微信自动回调的方法
*/**
    @RequestMapping("/callback")
    @ApiOperation(value = "第三方授权登录", notes = "第三方授权登录")
    public void socialCallback(@RequestParam(required = false) final String part,
                               @RequestParam final Integer type,
                               @SpringQueryMap AuthCallback callback,
                               HttpServletResponse response) {
        socialUserService.socialCallback(part,type, callback, response);
    }
}

serviceImpl方法

package com.公司简写.training.service.impl;

import com.公司简写.boot.service.impl.BaseServiceImpl;
import com.公司简写.cloud.authen.api.api.AuthTokenApi;
import com.公司简写.cloud.authen.api.dto.AuthTokenDTO;
import com.公司简写.cloud.authen.api.vo.AuthTokenVO;
import com.公司简写.cloud.usercenter.api.api.AuthenticationApi;
import com.公司简写.cloud.usercenter.api.dto.AuthSmsCodeDTO;
import com.公司简写.cloud.usercenter.api.enums.ExceptionEnum;
import com.公司简写.cloud.usercenter.api.vo.AuthSmsCodeVO;
import com.公司简写.framework.exception.InternalOutException;
import com.公司简写.framework.utils.base.ExceptionUtils;
import com.公司简写.training.api.dto.wechat.RegisterValidCodeDTO;
import com.公司简写.training.common.constants.AppCode;
import com.公司简写.training.common.enums.TerminalEnum;
import com.公司简写.training.common.model.TrainParent;
import com.公司简写.training.common.model.TrainTeacher;
import com.公司简写.training.common.vo.SocialVO;
import com.公司简写.training.config.WeChatMpProperty;
import com.公司简写.training.service.SocialUserService;
import com.公司简写.training.service.TrainParentService;
import com.公司简写.training.service.TrainTeacherService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.request.AuthWeChatMpRequest;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.util.Objects;

/**
 * * @description: 公众号登录
 * * @author: 
 * * @create: 2023/6/26 14:50
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class SocialUserServiceImpl extends BaseServiceImpl implements SocialUserService {

    private final TrainParentService parentService;

    private final TrainTeacherService teacherService;

    private final AuthTokenApi authTokenApi;

    private final AuthenticationApi authenticationApi;

    private final WeChatMpProperty weChatMpProperty;

    @Value("${sms_template_id}")
    private String sms_template_id;




//part=login.html  type=1
//authorizeUrl:https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxb90*****4f2de80&redirect_uri=https%3A%2F%2Fhy-test.cunwedu.com.cn%2Fh5%2Fsocial%2Fcallback%3Fpart%3Dlogin.html%26type%3D1&response_type=code&scope=snsapi_userinfo&
//  state=56d5a46bb89e8cb1e02bdc0ff2b8ffd4#wechat_redirect

    @Override
    public void renderAuth(String part, Integer type, HttpServletResponse response) {
        AuthRequest authRequest = getAuthRequest(part, type, response);
        String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
        if (log.isDebugEnabled()) {
            log.debug("微信网页授权获取用户基本信息链接:{}", authorizeUrl);
        }
        redirect(response, authorizeUrl);
    }

   //type是标识是老师还是家长授权
    @Override
    public void socialCallback(String part, Integer type, AuthCallback callback, HttpServletResponse response) {
        log.debug("第三方回调入参: part=[{}] ,type=[{}]", part, type);
        String accountId = null, account = null;
        try {
            AuthRequest authRequest = getAuthRequest(part, type, response);
            AuthResponse<AuthUser> authResponse = authRequest.login(callback);
            boolean isRegister = true;
            if (authResponse.ok()) {
                log.debug("第三方回调:第三方获取信息通过");
                AuthUser authUser = authResponse.getData();
                AuthToken authToken = authUser.getToken();
                String openId;
                String unionId = "";
                if (Objects.nonNull(authToken)) {
                    openId = authToken.getOpenId();
                    unionId = authToken.getUnionId();
                } else {
                    openId = authUser.getUuid();
                }
                String finalOpenId = openId;
                if (type.equals(TerminalEnum.WECHAT_APPLET_TEACHER.getCode())) {
                    //老师
                    TrainTeacher teacher = teacherService.queryList(
                                    q -> q.eq(TrainTeacher::getOpenId, finalOpenId))
                            .stream().findFirst().orElse(null);

                    if (Objects.nonNull(teacher)) {
                        isRegister = false;
                        //把帐号赋值 用于创建token
                        accountId = teacher.getUserId();
                        account = teacher.getUserAccount();
                    }
                } else {
                    //家长端
                    TrainParent parent = parentService.queryList(q -> q.eq(TrainParent::getOpenId, finalOpenId))
                            .stream().findFirst().orElse(null);

                    if (Objects.nonNull(parent)) {
                        isRegister = false;
                        //把帐号赋值 用于创建token
                        accountId = parent.getUserId();
                        account = parent.getUserAccount();
                    }
                }

                if (isRegister) {
                    redirectRegister(response, openId, unionId, part, type);
                    return;
                } else {

                    AuthTokenDTO dto = new AuthTokenDTO();
                    dto.setAppCode(AppCode.CODE);
                    dto.setUserId(accountId);
                    dto.setUserAccount(account);
                    AuthTokenVO token = validData(authTokenApi.create(dto));

                    SocialVO socialVO = new SocialVO();
                    socialVO.setAccessToken(token.getAccessToken());
                    socialVO.setAccountId(accountId);
                    socialVO.setOpenId(finalOpenId);
                    socialVO.setUnionId(unionId);
                    redirectLogin(response, socialVO, part, type);
                    return;
                }

            } else {
                log.info("登录失败: 第三方授权失败Code {}, Msg {}", authResponse.getCode(), authResponse.getMsg());
            }
        } catch (Exception e) {
            log.error("第三方登录异常:{}", ExceptionUtils.stackTraceText(e));
        }
        errorResponse(response);
    }


    /**
     * 重定向到登录页
     *
     * @param response
     * @param socialVO
     * @param part
     */
    private void redirectLogin(HttpServletResponse response, SocialVO socialVO, String part, Integer type) {
        String url = weChatMpProperty.getUrl();
        url += "?action=jump&token=" + socialVO.getAccessToken()
                + "&openId=" + socialVO.getOpenId()
                + "&accountId=" + socialVO.getAccountId();
        String unionId = socialVO.getUnionId();
        if (StringUtils.isNotEmpty(unionId)) {
            url += "&unionId=" + unionId;
        }
        url = dealPart(response, part, url, "&part=", type);

        log.debug("登录响应:跳转URL[{}]", url);

        redirect(response, url);
    }

    /**
     * 注册 response 处理
     *
     * @param response
     * @param openId
     * @param unionId
     * @param part
     */
    private void redirectRegister(HttpServletResponse response, String openId, String unionId, String part, Integer type) {
        String url = weChatMpProperty.getUrl();
        url += "?action=register&openId=" + openId;
        if (StringUtils.isNotEmpty(unionId)) {
            url += "&unionId=" + unionId;
        }

        url = dealPart(response, part, url, "&part=", type);

        log.debug("注册响应:跳转URL[{}]", url);

        redirect(response, url);
    }

    /**
     * 重定向
     *
     * @param response
     * @param url
     */
    private void redirect(HttpServletResponse response, String url) {
        try {
            response.sendRedirect(url);
        } catch (Exception e) {
            throw new InternalOutException(ExceptionEnum.OFFICIAL_ERROR);
        }
    }

    /**
     * 创建 request
     *
     * @param part     前端跳转到页面的标识
     * @param type     1.老师 2.家长
     * @param response
     * @return
     */
    public AuthRequest getAuthRequest(String part, Integer type, HttpServletResponse response) {
        String callbackUrl = weChatMpProperty.getCallbackUrl();
        callbackUrl = dealPart(response, part, callbackUrl, "?part=", type);

        return new AuthWeChatMpRequest(AuthConfig.builder()
                .clientId(weChatMpProperty.getClientId())
                .clientSecret(weChatMpProperty.getSecret())
                .redirectUri(callbackUrl)
                .build());
    }

    /**
     * 处理 part
     *
     * @param response
     * @param part
     * @param url
     * @param s
     * @return
     */
    private String dealPart(HttpServletResponse response, String part, String url, String s, Integer type) {
        if (StringUtils.isNoneBlank(part)) {
            try {
                part = URLEncoder.encode(part, "UTF-8");
            } catch (Exception e) {
                log.info("创建request异常:{}", ExceptionUtils.stackTraceText(e));
                errorResponse(response);
            }
            url += s + part + "&type=" + type;
        }
        return url;
    }


    /**
     * 异常错误 response 处理
     *
     * @param response
     */
    private void errorResponse(HttpServletResponse response) {
        String url = weChatMpProperty.getUrl();
        url += "?action=error";

        log.debug("异常响应:跳转URL[{}]", url);

        redirect(response, url);
    }

}

3. 微信回调方法处理完就会重定向到前端,前端根据url 后面拼接的参数判断是注册还是登录,继续往下处理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/762422.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LIMS系统应用于第三方实验室的意义

金现代LIMS实验室管理系统是将实验室业务从线下转到线上&#xff0c;按照 CNAS 规范进行合规化管理&#xff0c;并提升实验室工作效率的信息化系统。随着实验室业务的不断发展&#xff0c;实验室的规模逐渐扩大&#xff0c;样品数量和检测项目不断增加&#xff0c;数据管理需求…

客户报备小程序系统开发制作方案

客户报备系统小程序是一种用于公司业务人员进行客户管理和报备的小程序系统。 客户报备小程序系统主要功能包括以下几个方面&#xff1a; 1、用户注册与登录 提供用户注册和登录功能&#xff0c;确保用户可以使用个人账户登录系统。 2、报备信息录入 对于需要报备的客户&#x…

手把手教你搭建SpringCloud项目(三)集成Eureka服务注册中心

我们首先了解 Eureka&#xff1a;官方介绍 一、了解Eureka 1、什么是服务治理&#xff1f; Springcloud 封装了Netfix公司开发的Eureka模块来实现服务治理。在传统的RPC远程调用中&#xff0c;管理每个服务于服务之间依赖关系复杂&#xff0c;管理复杂&#xff0c;所以需要使…

113. 路径总和 II

113. 路径总和 II 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a; 原题链接&#xff1a; 113. 路径总和 II https://leetcode.cn/problems/path-sum-ii/ 完成情况&#xff1a; 解题思路&#xff1a; /**解题思路&#xff1a;* 和之前一…

msys2安装与配置: 在windows上使用linux工具链g++和包管理工具pacman C++开发

文章目录 为什么用这个msys2下载、doc安装&#xff0c;很简单初次运行&#xff0c;做些配置更新软件安装与卸载方法安装必要的软件包设置win环境变量在windows terminal中使用在vscode中使用 为什么用这个msys2 方便windows上的C开发demo&#xff0c;不需要VS了方便C开发安装o…

Redis缓存更新策略以及常见缓存问题

文章目录 一、什么是缓存&#xff1f;二、添加Redis缓存三、缓存更新策略四、缓存穿透五、缓存雪崩六、缓存击穿七、缓存工具封装 一、什么是缓存&#xff1f; 缓存就是数据交换的缓冲区(Cache)&#xff0c;是存储数据的临时地方&#xff0c;一般读写性能较好&#xff0c;常见…

Mac环境配置(Java)----使用bash_profile进行配置

1、打开软件--终端 2、首先查看本机Java的安装地址&#xff08;系统默认的&#xff09; /usr/libexec/java_home -V 查看到Java8安装的路径如下&#xff1a; 3、如果是第一次配置环境变量&#xff0c;使用命令&#xff1a;【touch .bash_profile】创建一个.bash_profile隐藏…

多表查询例题

目录 创建学生表 创建分数表 查看表结构 向两张表插入数据 1.查间student表的昕有记录 ​2.查间student表的第2条到4条记录 ​3.从student表查间所有学生的学号(id)、姓名(name)和院系(department)的信息 ​4.从student表中查间计算机系和英语系的学生的信息 ​5.从stu…

免费nas diy

安装Debian11 * 安装时选择ssh-server服务 * 安装时选中non-free contrib 还有bullseye-backports non-free 可以安装闭源驱动 bullseye-backports 可以更新内核 安装完成后,编辑/etc/apt/sources.list文件,关闭光驱源 并 切换到国内源 安装新内核6.1,重启后,可以移除老内…

监控指标111

P95、P99.9百分位数值——服务响应时间的重要衡量指标 开发技术 开发技术 2021-02-01 388次浏览 前段时间&#xff0c;在对系统进行改版后&#xff0c;经常会有用户投诉说页面响应较慢&#xff0c;我们看了看监控数据&#xff0c;发现从接口响应时间的平均值来看在500ms左右&…

数据结构--线性表以及其顺序存储结构

这里写目录标题 线性表的定义和特征定义特征 案例引入稀疏多项式链表实现多项式相加小结 线性表的类型定义&#xff08;抽象数据类型&#xff09;定义格式基本操作小结 线性表的顺序表示和实现实现1顺序存储表示顺序表中元素存储位置的计算 实现2顺序表的优点问题出现结构体表示…

你需要跟踪分析产品知识库的哪些关键数据

当你拥有一个产品知识库时&#xff0c;了解如何跟踪和分析关键数据指标是非常重要的。这些数据可以提供有关知识库使用情况、用户行为和满意度的宝贵见解。 在本文中&#xff0c;我们将探讨你需要跟踪的几个重要数据指标&#xff0c;以帮助你优化和改进产品知识库的效果和价值。…

大语言模型评估全解:评估流程、评估方法及常见问题

编者按&#xff1a;随着对大语言模型&#xff08;LLM&#xff09;评估领域的深入研究&#xff0c;我们更加清楚地认识到全面理解评估过程中的问题对于有效评估LLM至关重要。 本文探讨了机器学习模型评估中出现的常见问题&#xff0c;并深入研究了LLM对模型评估领域带来的重大挑…

Blazor 自定义可重用基础组件之 Dialog (Bootstrap Modal)

对话框是常用的组件之一&#xff0c;可以提供信息提示&#xff0c;也可以设置表单录入数据等。但是&#xff0c;Bootstrap Modal需要JS互操作&#xff0c;这个不太懂&#xff0c;只能绕过。这里没有一句JS代码&#xff0c;非常好用。 以下是具体代码&#xff1a; &#xfeff…

Drools用户手册翻译——第三章 构建,部署,应用和运行(六)剩余部分

终于是把这一章给看完了&#xff0c;看完也有点懵&#xff0c;需要重新梳理实践一下&#xff0c;最主要是概念有些多&#xff0c;不过还好&#xff0c;多用一用就明白了。 甩锅声明&#xff1a;本人英语一般&#xff0c;翻译只是为了做个笔记&#xff0c;所以有翻译错误的地方…

SciencePub学术 | 物联网类重点SCIEEI征稿中

SciencePub学术 刊源推荐: 物联网类重点SCIE&EI征稿中&#xff01;CCF推荐&#xff0c;对国人友好&#xff01;信息如下&#xff0c;录满为止&#xff1a; 一、期刊概况&#xff1a; 物联网类重点SCIE&EI 【期刊简介】IF&#xff1a;7.0-7.5&#xff0c;JCR1区&#…

算法训练营第四十一天||● 343. 整数拆分 96.不同的二叉搜索树

● 343. 整数拆分 这道有难度&#xff0c;不看题解肯定 想不到用动态规划&#xff0c;看了题解后能大概明白&#xff0c;但还不是很清晰&#xff0c;不太明白递推公式中强调的与dp[i]还要比较一次&#xff0c;也不明白第一次去最大最的那个比较 需要后面继续看 动规五部曲&a…

深度强化学习落地方法论训练篇:PPO、DQN、DDPG、学习率、折扣因子等

为了保证 DRL 算法能够顺利收敛,policy 性能达标并具有实用价值,结果有说服力且能复现,需要算法工作者在训练前、训练中和训练后提供全方位一条龙服务。我记得 GANs 刚火起来的时候,因为训练难度高,有人在 GitHub 上专门开了 repository,总结来自学术界和工业界的最新训练…

麦穗检测Y8S

采用YOLOV8训练&#xff0c;得到PT模型&#xff0c;然后直接转ONNX&#xff0c;使用OPENCV的DNN&#xff0c;不需要其他依赖&#xff0c;支持C/PYTHON 麦穗检测Y8S

CodeGeex论文阅读

《CodeGeeX: A Pre-Trained Model for Code Generation with Multilingual Evaluations on HumanEval-X》 论文地址&#xff1a;https://arxiv.org/pdf/2303.17568.pdf 代码地址&#xff1a;https://github.com/THUDM/CodeGe 一、简介 CodeGeeX&#xff0c;是一个具有130亿…