【springboot开发】微信登录

引言:除了常规的用户名密码登录,微信登录现在也变得常用起来,整理流程如下。

1. 引入依赖

        <!--httpclient-->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </dependency>
        <!--commons-io-->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
        <!--gson-->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
        </dependency>

2. 修改配置文件

为了获取对应的信息,需要先到链接: 微信平台申请,申请后会生成一个id和secret:
在这里插入图片描述
修改配置文件,id和secret和上面申请的需要一致:

# 微信开放平台 appid
wx:
  open:
    app_id: wx1292a69b2cd3c5b7
    # 微信开放平台 appsecret
    app_secret: dd776adcd6bb79a9a05a30e3a67ed7b3
    # 微信开放平台重定向url,即扫码登录后回调的后端api,中间的ip地址是内网穿透的
    redirect_url: http://17bbf738.r10.cpolar.top/buildBaseFrame/api/v1/user/wechat/login/wx

在控制类中使用@Value注解获取配置文件中的值:
在这里插入图片描述

3. 具体流程

完整流程如下:
在这里插入图片描述

3.1 用户发起微信登录请求

这里我们给出一种发起请求获取二维码的方法:

  • jsp页面
@RequestMapping("/doLogin")
    public ModelAndView doLogin(){
        ModelAndView modelAndView = new ModelAndView("admin/wechatLogin");

        log.info("前往登入页面");
        return modelAndView; // 跟页面模板名字一样才能跳转
    }

编写一个admin/wechatLogin.jsp文件用于后续展示扫码登录的二维码,其中redirect_url是扫码后的回调api:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Title</title>
	<script src="http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js">
	</script>
</head>
<body>
<div id="weixin"></div>
<script>
	var obj = new WxLogin({
		self_redirect:true,
		id:"weixin", // 要与你在那里生成二维码的div id 一致
		appid: "xxxxxxxxxxxxx", // 你申请的appid
		redirect_uri: encodeURIComponent("http://17bbf738.r10.cpolar.top/buildBaseFrame/api/v1/user/wechat/login/wx"),// 回调url,ip地址一定是内网穿透过的,然后你扫码后,微信官方返回一些参数(code,state)
		scope: "snsapi_login,snsapi_userinfo",// 你的权限
		state: "STATE",// 微信官方接口为了防止跨域攻击要加的参数 可以默认就这个
	});
</script>
</body>
</html>

3.2 验证微信登录操作

在jsp页面申请二维码后,微信平台会发出验证信息。
需要先在微信平台上输入重定向地址,这个地址是指向我们的验证信息接口的:
在这里插入图片描述
其中URL为用户向平台申请登录二维码后,微信发送验证消息的地址。
注意还需要在下面的地方修改域名:
在这里插入图片描述
在这里插入图片描述

验证的代码为:

@ResponseBody
    @GetMapping(value = "/check")   // 等价于@RequestMapping(value="/check",method=RequestMethod.GET)
    public String checkWxMsg(HttpServletRequest request) {
        log.info("进入微信校验的接口了");
        /**
         * 微信加密签名
         */
        String signature = request.getParameter("signature");
        /**
         * 随机字符串
         */
        String echostr = request.getParameter("echostr");
        /**
         * 时间戳
         */
        String timestamp = request.getParameter("timestamp");
        /**
         * 随机数
         */
        String nonce = request.getParameter("nonce");

        String[] str={timestamp,nonce, tmpToken};
        //将token、timestamp、nonce三个参数进行字典序排序
        Arrays.sort(str);
        StringBuffer sb = new StringBuffer();
        //将三个参数字符串拼接成一个字符串进行sha1加密
        for (String param:str) {
            sb.append(param);
        }

        //获取到加密过后的字符串
        String encryptStr = DigestUtils.sha1Hex(sb.toString());
//        String encryptStr = EncryptionUtil.encrypt("SHA1", sb.toString());
        //判断加密后的字符串是否与微信的签名一致
        if(signature.equalsIgnoreCase(encryptStr)){
            log.info("签名一致可以通过");
            return echostr;
        }

        log.error("这不是微信发来的消息!!");
        return null;
    }

微信收到验证通过的信息后会在上一步的jsp中显示登录的二维码。
在这里插入图片描述

3.3 扫码登录

扫码后调用api:

    @RequestMapping(value = "/login/wx",name = "进入微信登录方法")
    public CommonResult weixinlogin(String code, String state, HttpServletResponse response) {

        // 查看获取到的code
        log.info("进入微信登入方法,code为:{}, state为:{}",code,state);

        // 根据code获取access_token和openId
        // 微信请求地址标准格式url
        String getAccessTokenAndOpenIdUrl="https://api.weixin.qq.com/sns/oauth2/access_token?appid="+ appId +"&secret="+appSecret+"&code="+code+"&grant_type=authorization_code";

        // 向微信发送请求获取access_token与openid
        // restTemplate.getForObject:向远程api发送get请求,String.class表示设置response的类型为String
        Map map = JSON.parseObject(restTemplate.getForObject(getAccessTokenAndOpenIdUrl, String.class), Map.class);

        // 开始遍历参数
        map.forEach(
                (key,value)->{
                    log.info("根据code请求微信获取的值,key:{}, value:{}",key,value);
                }
        );

        // 获取accessToken
        String access_token = map.get("access_token").toString();

        // 获取openid
        String openid = map.get("openid").toString();

        // 再次请求微信平台,获取用户信息
        String getUserInfoUrl="https://api.weixin.qq.com/sns/userinfo?access_token="+access_token+"&openid="+openid+"&lang=zh_CN";

        // 发起请求
        Map userInfoMap = JSON.parseObject(restTemplate.getForObject(getUserInfoUrl, String.class), Map.class);
        userInfoMap.forEach((key, value)-> {
            log.info("微信获取用户信息,key为:{}, value为:{}",key,value);
        });

        WechatLoginDto wechatLoginDto = wechatLoginService.findByOpenId(openid);
        String name = (String) userInfoMap.get("nickname");
        UserInfoDto userInfoDto = service.getUserByname(name);

        // 首次登录则注册,否则就直接登录
        if(wechatLoginDto == null){

            wechatLoginDto = new WechatLoginDto();

            if(userInfoDto==null){
                userInfoDto = new UserInfoDto();
                userInfoDto.setNickname((String) userInfoMap.get("nickname"));
                userInfoDto.setAvatarUrl((String) userInfoMap.get("headimgurl"));
                userInfoDto.setIntroduction("");

                // 值为 1 时是男性,值为 2 时是女性,值为 0 时是未知
                int gender = (int) userInfoMap.get("sex");
                switch (gender){
                    case 1:
                        userInfoDto.setGender(GenderEnum.MALE);
                        break;
                    case 2:
                        userInfoDto.setGender(GenderEnum.FEMALE);
                        break;
                    default:
                        userInfoDto.setGender(GenderEnum.UNKNOWN);
                }

                Long userId = service.insertOneUser(userInfoDto);
                userInfoDto.setId(userId);
            }

            wechatLoginDto.setUserId(userInfoDto.getId());
            wechatLoginDto.setOpenId((String) userInfoMap.get("openid"));

            wechatLoginDto = wechatLoginService.insertOneWechatLogin(wechatLoginDto);
        }

        String jwt = jwtGenerator.createJwt(wechatLoginDto.getUserId());
        response.addHeader("Authorization", jwt);

        UserInfoVo userInfoVo = userApiConverter.toUserInfoVo(userInfoDto);

        // 把当前用户信息返回
        return CommonResult.success(userInfoVo);
    }

4. 注意事项

  • 本地测试(8080)时需要内网穿透,这里使用cpolar工具:
    打开cmd,在cmd中输入:
cpolar http 8080

用内网穿透的地址替换掉localhost:8080
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值