SpringBoot网站集成第三方微信扫码登录,已实测通过

微信实现扫码登录

一:具体流程:
  1、先登录你的 [微信开放平台](https://open.weixin.qq.com)
  2、创建网站应用
  3、设置你的AppSecret和授权回调域(==不用加http/https==)
  4、开始编码实现

二:实现效果
三:注意事项:
 

1、先登录你的 微信开放平台

SpringBoot网站集成第三方微信扫码登录,已实测通过_第1张图片
2、创建网站应用
  如果没有网站应用,需要先申请一个网站应用(需要填写公司的具体信息),填写无误,一切顺利的话,然后大概1个小时左右就会通过审核。

 SpringBoot网站集成第三方微信扫码登录,已实测通过_第2张图片

 

3、设置你的AppSecret和授权回调域(不用加http/https)
  在这里需要注意一个问题:因为在本地localhost进行测试,如果回调地址为localhost第三方微信将无法进行跳转。原因是外网访问不到本地,怎么办?

  解决办法:那就使用 ngrok 内网穿透把本地项目服务映射到公网,所以在测试时填写的回调地址是内网穿透时的访问域名。内网穿透工具–Sunny-Ngrok讲解

  如果你使用本人的代码的话,可以直接使用你公司服务器网站的域名(即你不用进行本地测试了,直接部署测试)

SpringBoot网站集成第三方微信扫码登录,已实测通过_第3张图片

 

4、开始编码实现

步骤一:创建一个继承AuthService的接口,WeChatAuthService,如下

public interface WeChatAuthService extends AuthService {
    public JSONObject getUserInfo(String accessToken, String openId);
}


步骤二:WeChatService的具体实现如下

@Service
public class WeChatAuthServiceImpl extends DefaultAuthServiceImpl implements WeChatAuthService {

    private Logger logger = LoggerFactory.getLogger(WeChatAuthServiceImpl.class);

//请求此地址即跳转到二维码登录界面
    private static final String AUTHORIZATION_URL =
            "https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect";

    // 获取用户 openid 和access——toke 的 URL
    private static final String ACCESSTOKE_OPENID_URL =
            "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";

    private static final String REFRESH_TOKEN_URL =
            "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s";

    private static final String USER_INFO_URL =
            "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN";

    private static final String APP_ID="xxxxxx";
    private static final String APP_SECRET="xxxxxx";
    private static final String SCOPE = "snsapi_login";

    private String callbackUrl = "https://www.xxx.cn/auth/wechat"; //回调域名

    @Override
    public String getAuthorizationUrl() throws UnsupportedEncodingException {
        callbackUrl = URLEncoder.encode(callbackUrl,"utf-8");
        String url = String.format(AUTHORIZATION_URL,APP_ID,callbackUrl,SCOPE,System.currentTimeMillis());
        return url;
    }


    @Override
    public String getAccessToken(String code) {
        String url = String.format(ACCESSTOKE_OPENID_URL,APP_ID,APP_SECRET,code);

        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
        URI uri = builder.build().encode().toUri();

        String resp = getRestTemplate().getForObject(uri, String.class);
        logger.error("getAccessToken resp = "+resp);
        if(resp.contains("openid")){
            JSONObject jsonObject = JSONObject.parseObject(resp);
            String access_token = jsonObject.getString("access_token");
            String openId = jsonObject.getString("openid");;

            JSONObject res = new JSONObject();
            res.put("access_token",access_token);
            res.put("openId",openId);
            res.put("refresh_token",jsonObject.getString("refresh_token"));

            return res.toJSONString();
        }else{
            throw new ServiceException("获取token失败,msg = "+resp);
        }
    }

    //微信接口中,token和openId是一起返回,故此方法不需实现
    @Override
    public String getOpenId(String accessToken) {
        return null;
    }

    @Override
    public JSONObject getUserInfo(String accessToken, String openId){
        String url = String.format(USER_INFO_URL, accessToken, openId);
        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
        URI uri = builder.build().encode().toUri();

        String resp = getRestTemplate().getForObject(uri, String.class);
        logger.error("getUserInfo resp = "+resp);
        if(resp.contains("errcode")){
            throw new ServiceException("获取用户信息错误,msg = "+resp);
        }else{
            JSONObject data =JSONObject.parseObject(resp);

            JSONObject result = new JSONObject();
            result.put("id",data.getString("unionid"));
            result.put("nickName",data.getString("nickname"));
            result.put("avatar",data.getString("headimgurl"));

            return result;
        }
    }

    //微信的token只有2小时的有效期,过时需要重新获取,所以官方提供了
    //根据refresh_token 刷新获取token的方法,本项目仅仅是获取用户
    //信息,并将信息存入库,所以两个小时也已经足够了
    @Override
    public String refreshToken(String refresh_token) {

        String url = String.format(REFRESH_TOKEN_URL,APP_ID,refresh_token);

        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
        URI uri = builder.build().encode().toUri();

        ResponseEntity resp = getRestTemplate().getForEntity(uri,JSONObject.class);
        JSONObject jsonObject = resp.getBody();

        String access_token = jsonObject.getString("access_token");
        return access_token;
    }
}


步骤三:
在Controller中调用,代码如下:

@RequestMapping(value = "/wxLoginPage",method = RequestMethod.GET)
    public JSONObject wxLoginPage() throws Exception {
        String uri = weChatAuthService.getAuthorizationUrl();
        return loginPage(uri);
    }

    @RequestMapping(value = "/wechat")
    public void callback(String code,HttpServletRequest request,HttpServletResponse response) throws Exception {
        String result = weChatAuthService.getAccessToken(code);
        JSONObject jsonObject = JSONObject.parseObject(result);

        String access_token = jsonObject.getString("access_token");
        String openId = jsonObject.getString("openId");
//        String refresh_token = jsonObject.getString("refresh_token");

        // 保存 access_token 到 cookie,两小时过期
        Cookie accessTokencookie = new Cookie("accessToken", access_token);
        accessTokencookie.setMaxAge(60 *2);
        response.addCookie(accessTokencookie);

        Cookie openIdCookie = new Cookie("openId", openId);
        openIdCookie.setMaxAge(60 *2);
        response.addCookie(openIdCookie);

        //根据openId判断用户是否已经登陆过
        KmsUser user = userService.getUserByCondition(openId);

        if (user == null) {
            response.sendRedirect(request.getContextPath() + "/student/html/index.min.html#/bind?type="+Constants.LOGIN_TYPE_WECHAT);
        } else {
            //如果用户已存在,则直接登录
            response.sendRedirect(request.getContextPath() + "/student/html/index.min.html#/app/home?open_id=" + openId);
        }
    }


步骤四:
前台js中,先请求auth/wxLoginPage,获取授权地址,等用户授权后会回调/auth/wechat,在此方法中进行逻辑处理即可。
 

注意事项:
1.在微信官网中配置回调域名的时候,不需要些http或https协议,只需要写上域即可,例如http://baidu.com,只需要填写baidu.com即可,如果是想要跳转到项目下面的某个Controller的某个方法中,如baidu.com/auth/wechat ,配置的时候也只需要配baidu.com,不需要指定后面的auth/wechat,后面的地址在代码中配置回调的地址的时候写上即可,代码中应该配置为https://baidu.com/auth/wechat
2.在跳转到授权二维码界面的时候,会遇到有的时候二维码出不来的状况,这是因为代码中的回调地址的问题,按照上面代码中的方式配置应该是没有问题的
 

本人花费2个月时间,整理了一套JAVA开发技术资料,内容涵盖java基础,分布式、微服务等主流技术资料,包含大厂面经,学习笔记、源码讲义、项目实战、讲解视频。


 希望可以帮助一些想通过自学提升能力的朋友,领取资料,扫码关注一下

记得关注公众号【编码师兄】

领取更多学习资料

你可能感兴趣的:(微信开发,spring,spring,boot,小程序,java)