微信小程序token方式登陆后端程序(springboot后端+redis 附源码)

微信官方文档:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html

参考文章:https://blog.csdn.net/csdnsevenn/article/details/86581917

只讲服务端的如何配置,微信端自己写吧。

知识点

openid:相当于一个微信用户的身份证,唯一标识一个微信用户。
code:前端通过微信提供的API wx.login({})得到的一个code,可以通过这个code获取openid和sessionkey。
token:令牌的意思,是服务端生成的一串字符串,作为客户端进行请求的一个标识,token可以是任何东西,只要能唯一标识你的用户就行,但尽量不要单纯用openid,不够安全,本次例子直接用uuid生成。
uuid:就是一个不会重复的值,通常可以作为主键,还是不懂可以百度一下
rawData:微信用户的基础信息,包括昵称之类的信息。

流程

首先大概讲一下流程吧,首先是后端获取前端传过来的rawData和code。然后再利用code获得openid存入用户表里,接着就利用uuid生成token,再返回token回前端,以后前端每次调用请求时就在请求头加上token,只要后端识别到相应的token就知道这是那一个用户。

redis的作用

token作为用户登陆的令牌,并且作为缓存的key值,存入到缓存中,方便后续直接从缓存中更快速的获取用户信息,而不用从数据库中获取。

  1. 首先是pom.xml。


    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.6.RELEASE
         
    
    com.example
    demo
    0.0.1-SNAPSHOT
    demo
    Demo project for Spring Boot

    
        1.8
    

    
        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        

        
            org.springframework.boot
            spring-boot-starter-web
        

        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            2.0.1
        

        
        
            mysql
            mysql-connector-java
        


        
        
            org.springframework.boot
            spring-boot-starter-data-redis
        
        
            org.apache.commons
            commons-pool2
        

        
        
            commons-codec
            commons-codec
            1.11
        



        
        
            org.apache.commons
            commons-lang3
            3.8.1
        

        
        
            c3p0
            c3p0
            0.9.1.2
        

        
        
            com.alibaba
            fastjson
            1.2.33
        

        
        
            com.squareup.okhttp3
            okhttp
            3.8.1
        



    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            

            
            
                org.mybatis.generator
                mybatis-generator-maven-plugin
                
                    src/main/resources/generatorConfig.xml
                    true
                    true
                
            

        
    



  1. 通过code获取openid的代码
public SessionDTO jscode2session(String code) {
       String url = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";
       OkHttpClient okHttpClient = new OkHttpClient();
       Request request = new Request.Builder()
               .addHeader("content-type", "application/json")
               .url(String.format(url, appid, secret, code))
               .build();
       try {
           Response execute = okHttpClient.newCall(request).execute();
           if (execute.isSuccessful()) {
           //获取openid等信息
               SessionDTO sessionDTO = JSON.parseObject(execute.body().string(), SessionDTO.class);
               return sessionDTO;
           } else {
               throw new ErrorCodeException(CommonErrorCode.OBTAIN_OPENID_ERROR);
           }

       } catch (IOException e) {
           throw new ErrorCodeException(CommonErrorCode.OBTAIN_OPENID_ERROR);
       }
   }

3.redis的配置(设置了序列化和反序列化,方便存储值为对象的键值对,记得值非string时不要使用@Cacheable注解,自己手写)


@Bean
   public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
       RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
       redisTemplate.setConnectionFactory(redisConnectionFactory);


       // 使用Jackson2JsonRedisSerialize 替换默认序列化
       Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

       ObjectMapper objectMapper = new ObjectMapper();
       objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
       objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
       jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

       // 设置value的序列化规则和 key的序列化规则
       redisTemplate.setKeySerializer(new StringRedisSerializer());
       redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
       redisTemplate.setHashKeySerializer(new StringRedisSerializer());
       redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
       redisTemplate.afterPropertiesSet();
       return redisTemplate;
   }
   
  1. redis的使用
//插入到数据库时顺便插入到缓存中
 @Override
   public User insertSelective(User record) {
       int flag=this.userMapper.insertSelective(record);
       if (flag==0){
           return null;
       }
       //插入成功就放入缓存
       stringRedisTemplate.opsForValue().set(record.getToken(),record);
       //这里是设置键的有效日期,不设置就是永久的token
//        stringRedisTemplate.expire(record.getToken(), 123L, TimeUnit.SECONDS);
       return record;
   }
  1. redis的测试
  @Test
   public void test(){
       ValueOperations operations=stringRedisTemplate.opsForValue();
       // 通过 token 从数据库中获取信息,如果没有验证失败
       // 如果通过一台设备登录,再通过另一台设备登录,第一台设备会自动登出
       // 此处已经将user放到缓存中,key值为token
       User openid=(User) operations.get("改成你的token值");
       System.out.println(openid.getToken());
   }
  1. contoller的编写
@RequestMapping("api/login")
   public ResultDTO login(@RequestBody LoginDTO loginDTO){
       try{
           //获取openid和session_key
           SessionDTO sessionDTO=wechatAdapter.jscode2session(loginDTO.getCode());
           //检验传过来的数据是否已被篡改
          // DigestUtil.checkDigest(loginDTO.getRawData(),loginDTO.getCode(),loginDTO.getSignature());
           //获取数据
           User user= JSON.parseObject(loginDTO.getRawData(),User.class);
           //生成用户个人的token
           String token= UUID.randomUUID().toString();
           Date date = new Date();
           //将user传到数据库中
           user.setToken(token);
           user.setUid(DateUtil.change_str(date));
           userService.insertSelective(user);
           TokenDTO data = new TokenDTO();
           data.setToken(token);

           return ResultDTO.ok(data);
       }catch (ErrorCodeException e){
           return ResultDTO.fail(e);
       }catch (Exception e){
           System.out.println(e.toString());
           return ResultDTO.fail(CommonErrorCode.UNKOWN_ERROR);
       }
   }

项目源码

服务器端地址:https://github.com/jiaojiaoyow/wx_login.git
(懒得写小程序端,就直接用其他人的了)
小程序端:https://github.com/codedrinker/jiuask

使用注意点,记得去application中更改appid和secret,generatorConfig.xml是逆向工程的,要使用的话得先配置一下(具体可以百度一下),还有拦截器一般是无法注入得,需要改配置(源码已经加了,做个提醒)。

@Bean
    public HandlerInterceptor getMyInterceptor(){
        return new LoginInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(getMyInterceptor());

    }

有什么问题欢迎留言哦,下一期微信做什么功能,也可以提出你的意见,当然,不是特别专业,有不好得地方请见谅,提一下你的意见给我

你可能感兴趣的:(微信小程序token方式登陆后端程序(springboot后端+redis 附源码))