当前位置:   article > 正文

微信小程序实现token登录_koa2 微信小程序登录 生成token

koa2 微信小程序登录 生成token

微信小程序实现token登录

微信小程序登录流程

img

前端先调用wx.login()接口获取code,再把code发个后端

login() {
  wx.login({
    success: (res) => {
      wx.request({
          url:"/login",
          method:"POST",
          data:{
              code:res
          },
          dataType:'json'
      })
    },
  })
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

后端采用是SpringSecurity+jwt+redis

@RestController
public class LoginController {

    @Autowired
    LoginService loginService;

    @PostMapping("/login")
    public R<Map<String,Object>> login(@RequestBody Map<String, String> params) {
        String code = params.get("code");
        if (StringUtils.isBlank(code)) {
            throw new ValidateException("code不能为空");
        }

        return loginService.login(code);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

后端接收code之后再发送http到微信官方获得openid

@Component
@ConfigurationProperties(prefix = "wx")
@Data
public class WxLogin {
    private  String appid;
    private  String secret;
    private  String grant_type;
    private  String wxurl;


    public String getOpenId(String code) throws IOException, URISyntaxException {
        URL url = new URL(wxurl);
        URI uri = new URIBuilder().setScheme(url.getProtocol())
                .setHost(url.getHost())
                .setPort(url.getPort())
                .setPath(url.getPath())
                .setParameters(
                        new BasicNameValuePair("appid",appid),
                        new BasicNameValuePair("secret",secret),
                        new BasicNameValuePair("js_code",code),
                        new BasicNameValuePair("grant_type",grant_type)
                ).build();

        HttpGet httpGet = new HttpGet(uri);

        CloseableHttpClient httpClient = HttpClientBuilder.create().build();

        // 配置信息
        RequestConfig requestConfig = RequestConfig.custom()
                // 设置连接超时时间(单位毫秒)
                .setConnectTimeout(5000)
                // 设置请求超时时间(单位毫秒)
                .setConnectionRequestTimeout(5000)
                // socket读写超时时间(单位毫秒)
                .setSocketTimeout(5000)
                // 设置是否允许重定向(默认为true)
                .setRedirectsEnabled(true).build();

        httpGet.setConfig(requestConfig);

        //响应
        CloseableHttpResponse response = httpClient.execute(httpGet);

        // 从响应模型中获取响应实体
        String openId = null;
        try {
            HttpEntity responseEntity = response.getEntity();
//            System.out.println("响应状态为:" + response.getStatusLine());
            if (StringUtils.isNull(responseEntity)) {
                throw new WxLoginException("响应体为空");
            }
//            System.out.println("响应内容长度为:" + responseEntity.getContentLength());
//            System.out.println("响应内容为:" + EntityUtils.toString(responseEntity));
            JSONObject json = JSON.parseObject(EntityUtils.toString(responseEntity));
            openId = json.getString("openid");
            if (StringUtils.isNull(openId)) {
                throw new WxLoginException("openid重复使用");
            }
        } finally {
            httpClient.close();
            response.close();
        }

        return openId;

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

通过opid查询数据库进行登录注册。

springsecurity登录流程

fd1374d3fe6d40d69f1c6500239308b2

@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private WxLogin wxLogin;

    @Autowired
    private UserService userService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private TokenService tokenService;

    @Override
    public R<Map<String, Object>> login(String code) {
        //得到openID
        String openId = null;
        try {
            openId = wxLogin.getOpenId(code);
        } catch (IOException | URISyntaxException e) {
            e.printStackTrace();
            return R.fail(HttpStatus.ERROR,"服务器请求异常");
        }
        //查询数据库是否存在openID
        boolean exist = true;
        //先查缓存再查数据库
        LoginUser loginUser = redisCache.getCacheObject(RedisCacheKeys.USERINFO_KEY + openId);
        if (StringUtils.isNull(loginUser)) {
            loginUser = new LoginUser();
        }
        if (StringUtils.isNull(loginUser.getUser())) {
            LambdaQueryWrapper<User> uqw = new LambdaQueryWrapper<>();
            uqw.eq(User::getOpenid,openId);
            User user = userService.getOne(uqw);
            if (StringUtils.isNull(user)) {
                exist = false;
            } else {
                loginUser.setUser(user);
                redisCache.setCacheObject(RedisCacheKeys.USERINFO_KEY+openId, loginUser);
            }
        }
        //不存在就注册,再登录
        if(!exist) {
            register(openId);
        }
        //springsecurity进行登录,存在就登录
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(openId, "null");
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);

        if (StringUtils.isNull(authenticate)) {
            throw new UsernameNotFoundException("用户名不出在!");
        }

        //封装
        LoginUser user = (LoginUser) authenticate.getPrincipal();

        //生成token
        String token = tokenService.createToken(user);
        UserInfoVo userInfo = BeanUtils.copyBean(loginUser.getUser(),UserInfoVo.class);

        HashMap<String, Object> res = new HashMap<String, Object>();
        res.put("token",token);
        res.put("userInfo",userInfo);
        return R.ok(res);
    }

    @Override
    public void register(String openId) {
        //
        User user = new User();
        user.setOpenid(openId);
        userService.save(user);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
token生成
@Component
public class TokenService
{
    // 令牌自定义标识
    @Value("${token.header}")
    private String header;

    // 令牌秘钥
    @Value("${token.secret}")
    private String secret;

    // 令牌有效期(默认30分钟)
    @Value("${token.expireTime}")
    private int expireTime;

    protected static final long MILLIS_SECOND = 1000;

    protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;

    protected static final long MILLIS_HOURS = 60 * MILLIS_MINUTE;

    private static final Long MILLIS_MINUTE_TEN = 60 * 60 * 1000L;

    @Autowired
    private RedisCache redisCache;

    /**
     * 获取用户身份信息
     *
     * @return 用户信息
     */
    public LoginUser getLoginUser(HttpServletRequest request)
    {
        // 获取请求携带的令牌
        String token = getToken(request);
        if (StringUtils.isNotEmpty(token))
        {
            try
            {
                Claims claims = parseToken(token);
                // 解析对应的权限以及用户信息
                String openid = (String) claims.get(Constants.LOGIN_USER_KEY);
                String userKey = getTokenKey(openid);
                return redisCache.getCacheObject(userKey);
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
        return null;
    }


    /**
     * 删除用户身份信息
     */
    public void delLoginUser(String token)
    {
        if (StringUtils.isNotEmpty(token))
        {
            String userKey = getTokenKey(token);
            redisCache.deleteObject(userKey);
        }
    }

    /**
     * 创建令牌
     *
     * @param loginUser 用户信息
     * @return 令牌
     */
    public String createToken(LoginUser loginUser)
    {
        refreshToken(loginUser);

        Map<String, Object> claims = new HashMap<>();
        claims.put(Constants.LOGIN_USER_KEY, loginUser.getUser().getOpenid());
        return createToken(claims);
    }

    /**
     * 验证令牌有效期,相差不足一个小时,自动刷新缓存
     *
     * @param loginUser
     * @return 令牌
     */
    public void verifyToken(LoginUser loginUser)
    {
        long expireTime = loginUser.getExpireTime();
        long currentTime = System.currentTimeMillis();
        if (expireTime - currentTime <= MILLIS_MINUTE_TEN)
        {
            refreshToken(loginUser);
        }
    }

    /**
     * 刷新令牌有效期
     *
     * @param loginUser 登录信息
     */
    public void refreshToken(LoginUser loginUser)
    {
        loginUser.setLoginTime(System.currentTimeMillis());
        loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_HOURS);
        // 根据uuid将loginUser缓存
        String userKey = getTokenKey(loginUser.getUser().getOpenid());
        redisCache.setCacheObject(userKey, loginUser,
                expireTime,TimeUnit.HOURS);
    }



    /**
     * 从数据声明生成令牌
     *
     * @param claims 数据声明
     * @return 令牌
     */
    private String createToken(Map<String, Object> claims)
    {
        return Jwts.builder()
                .setClaims(claims)
                .signWith(SignatureAlgorithm.HS512, secret).compact();
    }

    /**
     * 从令牌中获取数据声明
     *
     * @param token 令牌
     * @return 数据声明
     */
    private Claims parseToken(String token)
    {
        return Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     * 从令牌中获取用户名
     *
     * @param token 令牌
     * @return 用户名
     */
    public String getUsernameFromToken(String token)
    {
        Claims claims = parseToken(token);
        return claims.getSubject();
    }

    /**
     * 获取请求token
     *
     * @param request
     * @return token
     */
    private String getToken(HttpServletRequest request)
    {
        return request.getHeader(header);
    }

    private String getTokenKey(String openId)
    {
        return RedisCacheKeys.USERINFO_KEY + openId;
    }
}

    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172

完整流程图

image-20230305231830838

**
* 获取请求token
*
* @param request
* @return token
*/
private String getToken(HttpServletRequest request)
{
return request.getHeader(header);
}

private String getTokenKey(String openId)
{
    return RedisCacheKeys.USERINFO_KEY + openId;
}
  • 1
  • 2
  • 3
  • 4

}


完整流程图

[外链图片转存中...(img-KPgnRjWY-1678029553423)]

  • 1
  • 2
  • 3
  • 4
  • 5
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/266871
推荐阅读
  

闽ICP备14008679号