微信小程序登录后端

news2024/11/24 9:35:22

一、 概念

code

code是用户登录凭证,个人理解为用户的授权码(需要用户本人授权给小程序,小程序才有权力获取到你这个用户的数据),code需要由小程序向微信服务器获取。

注意: 每个code只能使用一次,且有效期为5分钟。因此,在使用code进行登录时,需要及时将其转换成用户的openid和session_key等信息,以免出现code过期的情况

openid

openid是用来唯一标识用户的一个字符串。在微信小程序中,每个用户的openid都是唯一的。通过openid,小程序可以获取用户的基本信息,如头像、昵称等。
大概就是,不同的用户,在不同的小程序上会有不同的openid,后台可以通过openid+session_key来对使用本小程序的用户进行标识(某个openid就是某个用户)

注意: 同一个用户在不同的小程序中拥有不同的openid。因此,在开发小程序时,不能使用openid来进行用户的唯一性判断。

二、 流程

流程图

在这里插入图片描述
步骤分析:

  1. 小程序端,调用wx.login()获取code授权码。调用wx.request()发送请求并携带code,请求开发者服务器(自己编写的后端服务)。
  2. 开发者服务端,通过HttpClient向微信接口服务发送请求,并携带appId+appsecret+code三个参数。
  3. 开发者服务端,接收微信接口服务返回的数据,session_key+opendId等。opendId是微信用户的唯一标识
  4. 开发者服务端,自定义登录态,生成令牌(token)和openid等数据返回给小程序端,方便后绪请求身份校验
  5. 小程序端,收到自定义登录态(token),存储storage。
  6. 小程序端,后绪通过wx.request()发起业务请求时,携带token。
  7. 开发者服务端,收到请求后,通过携带的token,解析当前登录用户的id。
  8. 开发者服务端,身份校验通过后,继续相关的业务逻辑处理,最终返回业务数据。

三、 服务端代码

配置文件

yml

项目:
	wechat:
	    appid: ${sky.wechat.appid}
	    secret: ${sky.wechat.secret}
#**配置为微信用户生成jwt令牌时使用的配置项:**
 	user-secret-key: itheima
    user-ttl: 7200000
    user-token-name: authentication

DTO传code

@Data
public class UserLoginDTO implements Serializable {

    private String code;

}

VO类

返回用户的id , openid,token给前端;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserLoginVO implements Serializable {

    private Long id;
    private String openid;
    private String token;

}

逻辑梳理

controller层

  1. 接收参数,获取code,校验数据;
  2. 给用户生成jwt令牌;

service层

  1. 通过code,向微信服务器发送请求获取openid
  2. 判断获取不获取得到(openid == null)
    2.1 为空 抛出业务异常(code可能是错误的);
  3. 判断是否为新用户(openid是否在数据库中已经存在)
    不存在 : 自动注册
    存在: 直接返回;

Controller

public class UserController {
    @Autowired
    private UserService userService;
    @Autowired
    private JwtProperties jwtProperties;

    @PostMapping("/login")
    @ApiOperation("微信登录")
    public Result<UserLoginVO> login(@PathVariable UserLoginDTO userLoginDTO){
        log.info("微信用户登录:{}",userLoginDTO.getCode());
        User user = userService.wxLogin(userLoginDTO);

        //登录成功后 为微信用户生成jwt令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtClaimsConstant.USER_ID, user.getId());
        String token = JwtUtil.createJWT(
                jwtProperties.getUserSecretKey(),
                jwtProperties.getUserTtl(),
                claims);

        UserLoginVO userLoginVO = UserLoginVO.builder()
                .id(user.getId())
                .openid(user.getOpenid())
                .token(token)
                .build();
        return Result.success(userLoginVO);
    }

}

ServiceImpl

public class UserServiceImpl implements UserService {
    @Autowired
    private WeChatProperties weChatProperties;
    @Autowired
    private UserMapper userMapper;

    //微信服务接口地址
    public static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session";

    /**
     * 微信登录
     * @param userLoginDTO
     * @return
     */
    public User wxLogin(UserLoginDTO userLoginDTO) {

            String openid = getOpenid(userLoginDTO.getCode());

            //1、 判断openid是否为空,如果为空表示登录失败,抛出业务异常
            if (openid == null) {
                throw new LoginFailedException(MessageConstant.LOGIN_FAILED);
            }

            //2、 判断当前用户是否为新用户
            User user = userMapper.getByOpenid(openid);

            //3、 如果是新用户,自动完成注册
            if (user == null) {
                user = User.builder()
                        .openid(openid)
                        .createTime(LocalDateTime.now())
                        .build();
                userMapper.insert(user);
            }

            //4、返回这个用户对象
            return user;
        }

    /**
         * 调用微信接口服务,获取微信用户的openid
         * @param code
         * @return
         */
        private String getOpenid (String code){
            //调用微信接口服务,获得当前微信用户的openid
            Map<String, String> map = new HashMap<>();
            map.put("appid", weChatProperties.getAppid());
            map.put("secret", weChatProperties.getSecret());
            map.put("js_code", code);
            map.put("grant_type", "authorization_code");
            String json = HttpClientUtil.doGet(WX_LOGIN, map);

            JSONObject jsonObject = JSON.parseObject(json);
            String openid = jsonObject.getString("openid");
            return openid;
        }

}

mapper 和 service接口就省略啦
mapper的insert记得键入主键的返回useGeneratedKeys=“true”

接着就是设置用户的 jwt令牌拦截器

@Component
@Slf4j
public class JwtTokenUserInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtProperties jwtProperties;

    /**
     * 校验jwt
     *
     * @param request
     * @param response
     * @param handler   目标方法
     * @return true ,代表放行, false,表示禁止放行
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判断当前拦截到的是Controller的方法还是其他资源
        if (!(handler instanceof HandlerMethod)) {
            //当前拦截到的不是动态方法,直接放行
            return true;
        }

        //1、从请求头中获取令牌   因为token存放在请求头中,
        String token = request.getHeader(jwtProperties.getUserTokenName());

        //2、校验令牌
        try {
            log.info("jwt校验:{}", token);
            Claims claims = JwtUtil.parseJWT(jwtProperties.getUserSecretKey(), token);
            Long userId = Long.valueOf(claims.get(JwtClaimsConstant.USER_ID).toString());
            log.info("当前用户id:", userId);
            BaseContext.setCurrentId(userId); //通过LocalThread,把id存到该线程的存储空间中;
            //3、通过,放行
            return true;
        } catch (Exception ex) {
            //4、不通过,响应401状态码
            response.setStatus(401);
            return false;
        }
    }

WebMvcConfiguration配置拦截器;

 protected void addInterceptors(InterceptorRegistry registry) {
        log.info("开始注册自定义拦截器...");
        registry.addInterceptor(jwtTokenUserInterceptor)
                .addPathPatterns("/user/**")
                .excludePathPatterns("/user/user/login")
                .excludePathPatterns("/user/shop/status");
    }

参考链接:https://juejin.cn/post/7212074532340908091

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

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

相关文章

射频功率放大器应用中GaN HEMT的表面电势模型

标题&#xff1a;A surface-potential based model for GaN HEMTs in RF power amplifier applications 来源&#xff1a;IEEE IEDM 2010 本文中的任何第一人称都为论文的直译 摘要&#xff1a;我们提出了第一个基于表面电位的射频GaN HEMTs紧凑模型&#xff0c;并将我们的工…

kubernetes集群编排——k8s认证授权

pod绑定sa [rootk8s2 ~]# kubectl create sa admin [rootk8s2 secret]# vim pod5.yaml apiVersion: v1 kind: Pod metadata:name: mypod spec:serviceAccountName: admincontainers:- name: nginximage: nginxkubectl apply -f pod5.yamlkubectl get pod -o yaml 认证 [rootk8s…

SpringBoot案例学习(黑马程序员day10,day11)

1 环境准备&#xff1a; 1.idea 创建spring项目&#xff0c;选择springweb,mybatis framework ,sql drive框架 2.添加pom.xml依赖&#xff1a; <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependen…

关于 pthread_create 传参的疑问

对于函数原型 int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) 里的参数 arg&#xff0c;之前一直有疑问&#xff0c;就是把 &thread 传给 arg时&#xff0c;新创建的线程里是否能取到这个值呢&#xff1…

小程序多文件上传 Tdesign

众所周知&#xff0c;小程序文件上传还是有点麻烦的&#xff0c;其实主要还是小程序对的接口有诸多的不便&#xff0c;比如说&#xff0c;文件不能批量提交&#xff0c;只能一个个的提交&#xff0c;小程序的上传需要专门的接口。 普通的小程序的页面也比普通的HTML复杂很多 现…

SQL SERVER Inregration Services-OLE DB、Oracle和ODBC操作

OLE DB链接器 OLE DB插件下载&#xff1a;https://learn.microsoft.com/zh-cn/sql/connect/oledb/download-oledb-driver-for-sql-server?viewsql-server-ver16 配置OLE DB Connection Manager 在点击“新建”时&#xff0c;会弹出警告信息“不支持指定的提供程序&#xff0…

SpringBoot系列之集成Redission入门与实践教程

Redisson是一款基于java开发的开源项目&#xff0c;提供了很多企业级实践&#xff0c;比如分布式锁、消息队列、异步执行等功能。本文基于Springboot2版本集成redisson-spring-boot-starter实现redisson的基本应用 软件环境&#xff1a; JDK 1.8 SpringBoot 2.2.1 Maven 3.2…

k8s 目录和文件挂载到宿主机

k8s生产中常用的volumes挂载方式有&#xff1a;hostPath、pv&#xff0c;pvc、nfs 1.hostPath挂载 hostPath是将主机节点文件系统上的文件或目录挂载到Pod 中&#xff0c;同时pod中的目录或者文件也会实时存在宿主机上&#xff0c;如果pod删除&#xff0c;hostpath中的文…

CANoe测试报告如何打印表格?

文章目录 效果使用函数TestInfoTableTestInfoHeadingBeginTestInfoCellTestInfoHeadingEndTestInfoRow代码效果 使用函数 以下函数使用方法查看帮助文档。 TestInfoTable TestInfoHeadingBegin TestInfoCell TestInfoHeadingEnd TestInfoRow 代码

css设置浏览器表单自动填充时的背景

浏览器自动填充表单内容&#xff0c;会自动设置背景色。对于一般的用户&#xff0c;也许不会觉得有什么&#xff0c;但对于要求比较严格的用户&#xff0c;就会“指手画脚”。这里&#xff0c;我们通过css属性来设置浏览器填充背景的过渡时间&#xff0c;使用户看不到过渡后的背…

Python之字符串、正则表达式练习

目录 1、输出随机字符串2、货币的转换&#xff08;字符串 crr107&#xff09;3、凯撒加密&#xff08;book 实验 19&#xff09;4、字符替换5、检测字母或数字6、纠正字母7、输出英文中所有长度为3个字母的单词 1、输出随机字符串 编写程序&#xff0c;输出由英文字母大小写或…

相亲交友小程序源码 同城相亲交友小程序源码

相亲交友小程序源码 同城相亲交友小程序源码 收费模式&#xff1a; 1、会员开通VIP收费&#xff1b;3、会员购买服务项目收费&#xff08;可以自定义服务项目&#xff09;&#xff1b; 二、全民推广系统&#xff1a; 1、邀请用户注册奖励&#xff08;邀请一个用户进入注册…

基础:JavaScript的怪癖之一:提升(Hoisting)

JavaScript&#xff0c;通常被称为“Web 语言”&#xff0c;是一种多功能且广泛使用的编程语言。它以其怪癖而闻名&#xff0c;其中之一就是 hoisting&#xff08;提升&#xff09;。无论你是经验丰富的开发人员还是刚刚开始你的编码之旅&#xff0c;理解提升对于编写干净和高效…

设计模式-状态模式 golang实现

一 什么是有限状态机 有限状态机&#xff0c;英⽂翻译是 Finite State Machine&#xff0c;缩写为 FSM&#xff0c;简称为状态机。 状态机不是指一台实际机器&#xff0c;而是指一个数学模型。说白了&#xff0c;一般就是指一张状态转换图。 已订单交易为例&#xff1a; 1.…

绿光集团荣获美业科技创新大奖,杨全军董事长荣获杰出人物

近日&#xff0c;在2023中国&#xff08;南昌&#xff09;国际美发美容节之“凤凰之夜&#xff0c;美业盛典”上&#xff0c;香港绿光国际科技集团股份有限公司董事长杨全军先生荣获了2023年度“凤凰”杰出人物奖。同时&#xff0c;绿光集团也因其研发的AI人工智能数字光磁床、…

第21章_InnoDB数据页结构

文章目录 概述UserRecords和FreeSpaceInfimum Supremum&#xff08;最小记录和最大记录&#xff09;File Header&#xff08;文件头部&#xff09;Page Directory&#xff08;页目录&#xff09;File Trailer 概述 它是InnoDB管理存储空间的基本单位&#xff0c;一个页的大小…

【3D图像分割】基于Pytorch的 VNet 3D 图像分割4(改写数据流篇)

在这篇文章&#xff1a;【3D 图像分割】基于 Pytorch 的 VNet 3D 图像分割2&#xff08;基础数据流篇&#xff09; 的最后&#xff0c;我们提到了&#xff1a; 在采用vent模型进行3d数据的分割训练任务中&#xff0c;输入大小是16*96*96&#xff0c;这个的裁剪是放到Dataset类…

C++中如何获取虚表和虚函数的地址

获取虚函数的地址 虚函数是C中用于实现多态的一种机制&#xff0c;该机制的原理在此不做赘述。本文主要讨论如何获取虚表以及虚函数的地址&#xff1f; class ClassA { private:int _a;double _b; public:ClassA(int a, double b) : _a(a), _b(b) { }virtual int funcA(int a…

设计模式之组合模式-创建层次化的对象结构

目录 概述概念主要角色应用场景 组合模式的实现类图NS图基本代码组合模式的精髓意外收获&#xff08;❀❀&#xff09; 应用示例-公司组织架构管理需求结构图代码 组合模式的优缺点优点缺点 总结 概述 概念 组合模式是一种结构型设计模式&#xff0c;它允许将对象组合成树形结…

xshell和linux什么关系,其实很简单

如果你是从事网络安全相关的工作人员&#xff0c;那你一定对很多人xshell和linux这两词很熟悉&#xff0c;那么xshell和linux究竟是什么关系呢&#xff1f;今天就让小编给你详细讲讲。 xshell和linux什么关系 一、xshell和linux什么关系 Xsehll是一款在Windows平台上运行的远…