美文网首页
微信小程序登录实现(spring boot版)

微信小程序登录实现(spring boot版)

作者: 归来_仍是少年 | 来源:发表于2020-10-31 12:27 被阅读0次
    1. 引入相关依赖
        <!-- jwt -->
            <dependency>
                <groupId>com.auth0</groupId>
                <artifactId>java-jwt</artifactId>
                <version>3.9.0</version>
            </dependency>
        <!-- 对接微信平台 -->
            <dependency>
                <groupId>com.github.binarywang</groupId>
                <artifactId>weixin-java-common</artifactId>
                <version>3.9.0</version>
            </dependency>
            <dependency>
                <groupId>com.github.binarywang</groupId>
                <artifactId>weixin-java-miniapp</artifactId>
                <version>3.9.0</version>
            </dependency>
    
    
    1. 配置小程序依赖
    在yml文件中添加
    wx:
      mini:
        appid: 小程序appid
        secret: 小程序secret
    
    新建两个配置文件
    @Configuration
    @ConfigurationProperties(prefix = "wx.mini")
    @Data
    public class WechatLoginProperties {
        private String appid;
        private String secret;
    }
    
    @Configuration
    @ConditionalOnClass(WxMaService.class)
    @EnableConfigurationProperties(WechatLoginProperties.class)
    public class WxMaConfiguration {
        @Autowired
        private WechatLoginProperties wechatLoginProperties;
    
        @Bean
        @ConditionalOnMissingBean
        public WxMaConfig wxMaConfig(){
            WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
            config.setAppid(wechatLoginProperties.getAppid());
            config.setSecret(wechatLoginProperties.getSecret());
            config.setMsgDataFormat("JSON");
            return config;
        }
    
        @Bean
        public WxMaService wxMaService(WxMaConfig maConfig) {
            WxMaService service = new WxMaServiceImpl();
            service.setWxMaConfig(maConfig);
            return service;
        }
    }
    
    1. 实现token工具类
    @Slf4j
    @Component
    public class TokenUtil {
        // 过期时间6个小时
        private static final long EXPIRE_TIME = 6 * 60 * 60 * 1000;
    
        private static final String AUTHORITIES_KEY = "auth";
    
        private static final String SECRET = "KeXu6IgYf7xa";
    
        public static final String CACHE_USERINFO = "miniUserInfo";
    
        @Autowired
        private MiniUserInfoMapper miniUserInfoMapper;
    
        @Autowired
        private CacheManager cacheManager;
    
        /**
         * 校验token是否正确
         *
         * @param token 密钥
         * @return 是否正确
         */
        public boolean verify(String token, MiniUserInfo miniUserInfo) {
            try {
                Algorithm algorithm = Algorithm.HMAC256(SECRET);
                JWTVerifier verifier = JWT.require(algorithm)
                        .withClaim(AUTHORITIES_KEY, JSONUtil.toJsonStr(miniUserInfo))
                        .build();
                DecodedJWT jwt = verifier.verify(token);
                return true;
            } catch (Exception exception) {
                return false;
            }
        }
    
        /**
         * 获得token中的信息无需secret解密也能获得
         *
         * @return 用户信息
         */
        public MiniUserInfo getUserFromJwt(String token) {
            try {
                DecodedJWT jwt = JWT.decode(token);
                String asString = jwt.getClaim(AUTHORITIES_KEY).asString();
                return JSONUtil.toBean(asString, MiniUserInfo.class);
            } catch (JWTDecodeException e) {
                return null;
            }
        }
    
        /**
         * 生成签名,EXPIRE_TIME后过期
         *
         * @return 加密的token
         */
        public String sign(MiniUserInfo miniUserInfo) {
            try {
                Algorithm algorithm = Algorithm.HMAC256(SECRET);
                return JWT.create()
                        .withClaim(AUTHORITIES_KEY, JSONUtil.toJsonStr(miniUserInfo))
                        .withExpiresAt(DateUtil.date(DateUtil.currentSeconds() + EXPIRE_TIME))
                        .sign(algorithm);
            } catch (Exception e) {
                return null;
            }
        }
    
        public String getToken() {
            String token;
            HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
            token = request.getHeader("Token");
            if (StringUtils.isBlank(token)) {
                return "";
            }
            return token;
        }
    
        /**
         * 获取用户信息 从加密token中获取
         *
         * @return MiniUserInfo
         */
        public MiniUserInfo getLoginUserWithToken() {
            try {
                String token = this.getToken();
                if (StringUtils.isBlank(token)) {
                    return null;
                }
                MiniUserInfo userFromJwt = getUserFromJwt(token);
                if (ObjectUtil.isNull(userFromJwt)) {
                    return null;
                }
                return userFromJwt;
            } catch (Exception e) {   //token不存在
                return null;
            }
        }
    
        /**
         * 获取用户信息 先走缓存再走数据库
         *
         * @return MiniUserInfo
         */
        public MiniUserInfo getLoginUser() {
            try {
                log.info("开始->获取用户信息");
                String token = this.getToken();
                log.info("获取token [{}] ", token);
                if (!StringUtils.isNotBlank(token)) {
                    return null;
                }
    
                MiniUserInfo userFromJwt = getUserFromJwt(token);
                if (ObjectUtil.isNull(userFromJwt)) {
                    return null;
                }
                log.info("解密toke获取用户id : [{}],  openId : [{}] ", userFromJwt.getId(), userFromJwt.getOpenId());
                if (ObjectUtil.isNull(userFromJwt.getOpenId())) {
                    return null;
                }
    
                MiniUserInfo miniUserInfo;
                Cache cache = cacheManager.getCache(CACHE_USERINFO);
                if (ObjectUtil.isNull(cache)) {
                    miniUserInfo = miniUserInfoMapper.selectOne(Wrappers.<MiniUserInfo>lambdaQuery().eq(MiniUserInfo::getOpenId, userFromJwt.getOpenId()));
                    log.info("cache为空从数据库中获取用户信息 : [{}]", miniUserInfo);
                } else {
                    miniUserInfo = cache.get(userFromJwt.getOpenId(), MiniUserInfo.class);
                    log.info("从缓存获取用户信息 : [{}]", miniUserInfo);
                    if (ObjectUtil.isNull(miniUserInfo)) {
                        miniUserInfo = miniUserInfoMapper.selectOne(Wrappers.<MiniUserInfo>lambdaQuery().eq(MiniUserInfo::getOpenId, userFromJwt.getOpenId()));
                        log.info("缓存过期从数据库中获取用户信息 : [{}]", miniUserInfo);
                        cache.put(userFromJwt.getOpenId(), miniUserInfo);
                    }
                }
    
                if (ObjectUtil.isNull(miniUserInfo)) {
                    return null;
                }
                log.info("结束->获取用户信息");
                return miniUserInfo;
            } catch (Exception e) {   //token不存在
                return null;
            }
        }
    }
    
    
    1. 实现登录
    创建登录接口
    public interface LoginService {
    
       WxLoginResponse loginByWeChat(WxLoginRequest request);
    }
    
    实现登录类和方法
    @Slf4j
    @Service
    public class LoginServiceImpl implements LoginService {
    
        @Autowired
        private MiniUserInfoMapper miniUserInfoMapper;
        @Autowired
        private WxMaService wxService;
        @Autowired
        private TokenUtil tokenUtil;
    
        @Transactional(rollbackFor = Exception.class)
        @Override
        public WxLoginResponse loginByWeChat(WxLoginRequest request) {
            String token, sessionKey, openId, unionId;
            val response = new WxLoginResponse();
    
            try {
                WxMaJscode2SessionResult result = this.wxService.getUserService().getSessionInfo(request.getCode());
                unionId = result.getUnionid();
                sessionKey = result.getSessionKey();
                openId = result.getOpenid();
            } catch (WxErrorException e) {
                log.error("获取openid获取失败 : {}", e.getMessage());
                throw new NormalException("openid获取失败");
            }
    
            if (StringUtils.isNotBlank(openId) || StringUtils.isNotBlank(sessionKey)) {
    
                MiniUserInfo miniUserInfo = miniUserInfoMapper.selectOne(Wrappers.<MiniUserInfo>lambdaQuery().eq(MiniUserInfo::getOpenId, openId));
                if (ObjectUtil.isNotNull(miniUserInfo)) {
    
                    miniUserInfo.setSessionKey(sessionKey);
                    miniUserInfoMapper.updateById(miniUserInfo);
                    BeanUtils.copyProperties(miniUserInfo, response);
                    token = tokenUtil.sign(miniUserInfo);
                    log.info("登录成功----------生成token : {} ", token);
                    response.setToken(token);
                    return response;
                }
    
                MiniUserInfo newMiniUser = new MiniUserInfo();
                BeanUtils.copyProperties(request, newMiniUser);
                newMiniUser.setOpenId(openId)
                        .setSessionKey(sessionKey)
                        .setUnionId(unionId)
                        .setSalt(RandomStringUtils.randomAlphabetic(6));
                miniUserInfoMapper.insert(newMiniUser);
    
                token = tokenUtil.sign(newMiniUser);
                log.info("注册成功----------生成token : {} ", token);
                BeanUtils.copyProperties(newMiniUser, response);
                response.setToken(token);
                return response;
            }
            throw new NormalException("用户登录失败");
        }
    }
    
    
    1. 暴露登录接口
    @Api(value = "/api/login", tags = {"小程序用户登录"})
    @RequestMapping("/api/login")
    @RestController
    public class LoginController {
    
        @Autowired
        private LoginService loginService;
    
        @PostMapping("/login")
        @ApiOperation(value = "小程序登录")
        public Result<WxLoginResponse> loginByWechat(@RequestBody WxLoginRequest request) {
            WxLoginResponse response = loginService.loginByWeChat(request);
            return Result.<WxLoginResponse>builder().success().data(response).build();
        }
    }
    
    

    相关文章

      网友评论

          本文标题:微信小程序登录实现(spring boot版)

          本文链接:https://www.haomeiwen.com/subject/jajsvktx.html