Spring Boot如何轻松实现微信扫码登录,效果竟然如此惊艳?

2026-05-22 06:231阅读0评论SEO基础
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1695个文字,预计阅读时间需要7分钟。

Spring Boot如何轻松实现微信扫码登录,效果竟然如此惊艳?

微信开放平台:微信扫码登录功能+官方文档:https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.

1.授权流程说明:微信OAuth2.0授权登录,让微信用户安全登录

Spring Boot如何轻松实现微信扫码登录,效果竟然如此惊艳?

微信开放平台:微信扫码登录功能

官方文档:developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html

1. 授权流程说明

微信OAuth2.0授权登录让微信用户使用微信身份安全登录第三方应用或网站,在微信用户授权登录已接入微信OAuth2.0的第三方应用后,第三方可以获取到用户的接口调用凭证(access_token),通过access_token可以进行微信开放平台授权关系接口调用,从而可实现获取微信用户基本开放信息和帮助用户实现基础开放功能等。

微信OAuth2.0授权登录目前支持authorization_code模式,适用于拥有server端的应用授权。该模式整体流程为:

① 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据code参数;

② 通过code参数加上AppID和AppSecret等,通过API换取access_token;

③ 通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。

第一步:请求CODE

第三方使用网站应用授权登录前请注意已获取相应网页授权作用域(scope=snsapi_login),则可以通过在PC端打开以下链接:open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

返回说明

用户允许授权后,将会重定向到redirect_uri的网址上,并且带上code和state参数

redirect_uri?code=CODE&state=STATE

若用户禁止授权,则重定向后不会带上code参数,仅会带上state参数

redirect_uri?state=STATE

例如:登录一号店网站应用 passport.yhd.com/wechat/login.do 打开后,一号店会生成state参数,跳转到 open.weixin.qq.com/connect/qrconnect?appid=wxbdc5610cc59c1631&redirect_uri=passport.yhd.com/wechat/callback.do?code=CODE&state=3d6be0a4035d839573b04816624a415e

第二步:通过code获取access_token

通过code获取access_token

api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

返回说明

正确的返回:

{ "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE", "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL" }

错误返回样例:

{"errcode":40029,"errmsg":"invalid code"}

  • Appsecret 是应用接口使用密钥,泄漏后将可能导致应用数据泄漏、应用的用户数据泄漏等高风险后果;存储在客户端,极有可能被恶意窃取(如反编译获取Appsecret);
  • access_token 为用户授权第三方应用发起接口调用的凭证(相当于用户登录态),存储在客户端,可能出现恶意获取access_token 后导致的用户数据泄漏、用户微信相关接口功能被恶意发起等行为;
  • refresh_token 为用户授权第三方应用的长效凭证,仅用于刷新access_token,但泄漏后相当于access_token 泄漏,风险同上。

建议将secret、用户数据(如access_token)放在App云端服务器,由云端中转接口调用请求。

第三步:通过access_token调用接口

获取access_token后,进行接口调用,有以下前提:

  1. access_token有效且未超时;
  2. 微信用户已授权给第三方应用帐号相应接口作用域(scope)。

对于接口作用域(scope),能调用的接口有以下:

2. 授权流程代码

因为微信开放平台的AppiD和APPSecret和微信公众平台的AppiD和AppSecret都是不同的,因此需要配置一下:

# 开放平台 wechat.open-app-id=wx6ad144e54af67d87 wechat.open-app-secret=91a2ff6d38a2bbccfb7e9f9079108e2e @Data @Component @ConfigurationProperties(prefix = "wechat") public class WechatAccountConfig { //公众号appid private String mpAppId; //公众号appSecret private String mpAppSecret; //商户号 private String mchId; //商户秘钥 private String mchKey; //商户证书路径 private String keyPath; //微信支付异步通知 private String notifyUrl; //开放平台id private String openAppId; //开放平台秘钥 private String openAppSecret; } @Configuration public class WechatOpenConfig { @Autowired private WechatAccountConfig accountConfig; @Bean public WxMpService wxOpenService() { WxMpService wxOpenService = new WxMpServiceImpl(); wxOpenService.setWxMpConfigStorage(wxOpenConfigStorage()); return wxOpenService; } @Bean public WxMpConfigStorage wxOpenConfigStorage() { WxMpInMemoryConfigStorage wxMpInMemoryConfigStorage = new WxMpInMemoryConfigStorage(); wxMpInMemoryConfigStorage.setAppId(accountConfig.getOpenAppId()); wxMpInMemoryConfigStorage.setSecret(accountConfig.getOpenAppSecret()); return wxMpInMemoryConfigStorage; } } @Controller @RequestMapping("/wechat") @Slf4j public class WeChatController { @Autowired private WxMpService wxMpService; @Autowired private WxMpService wxOpenService; @GetMapping("/qrAuthorize") public String qrAuthorize() { //returnUrl就是用户授权同意后回调的地址 String returnUrl = "heng.nat300.top/sell/wechat/qrUserInfo"; //引导用户访问这个链接,进行授权 String url = wxOpenService.buildQrConnectUrl(returnUrl, WxConsts.QRCONNECT_SCOPE_SNSAPI_LOGIN, URLEncoder.encode(returnUrl)); return "redirect:" + url; } //用户授权同意后回调的地址,从请求参数中获取code @GetMapping("/qrUserInfo") public String qrUserInfo(@RequestParam("code") String code) { WxMpOAuth2AccessToken wxMpOAuth2AccessToken = new WxMpOAuth2AccessToken(); try { //通过code获取access_token wxMpOAuth2AccessToken = wxOpenService.oauth2getAccessToken(code); } catch (WxErrorException e) { log.error("{}", e); throw new SellException(ResultEnum.WECHAT_MP_ERROR.getCode(), e.getError().getErrorMsg()); } //从token中获取openid String openId = wxMpOAuth2AccessToken.getOpenId(); //这个地址可有可无,反正只是为了拿到openid,但是如果没有会报404错误,为了好看随便返回一个百度的地址 String returnUrl = "www.baidu.com"; log.info("openid={}", openId); return "redirect:" + returnUrl + "?openid="+openId; } }

请求路径:在浏览器打开

open.weixin.qq.com/connect/qrconnect?appid=wx6ad144e54af67d87&redirect_uri=heng.nat300.top/sell/seller/order/list"); } @GetMapping("/logout") public ModelAndView logout(HttpServletRequest request, HttpServletResponse response, Map<String, Object> map) { //1. 从cookie里查询 Cookie cookie = CookieUtil.get(request, CookieConstant.TOKEN); if (cookie != null) { //2. 清除redis redisTemplate.opsForValue().getOperations().delete(String.format(RedisConstant.TOKEN_PREFIX, cookie.getValue())); //3. 清除cookie CookieUtil.set(response, CookieConstant.TOKEN, null, 0); } map.put("msg", ResultEnum.LOGOUT_SUCCESS.getMessage()); map.put("url", "/sell/seller/order/list"); return new ModelAndView("common/success", map); } }

① 将上一步获取到的openid存入数据库

② 将授权后跳转的地址改为登录地址

//用户授权同意后回调的地址,从请求参数中获取code @GetMapping("/qrUserInfo") public String qrUserInfo(@RequestParam("code") String code) { WxMpOAuth2AccessToken wxMpOAuth2AccessToken = new WxMpOAuth2AccessToken(); try { //通过code获取access_token wxMpOAuth2AccessToken = wxOpenService.oauth2getAccessToken(code); } catch (WxErrorException e) { log.error("{}", e); throw new SellException(ResultEnum.WECHAT_MP_ERROR.getCode(), e.getError().getErrorMsg()); } //从token中获取openid String openId = wxMpOAuth2AccessToken.getOpenId(); //授权成功后跳转到卖家系统的登录地址 String returnUrl = "heng.nat300.top/sell/seller/login"; log.info("openid={}", openId); return "redirect:" + returnUrl + "?openid="+openId; }

③ 在浏览器请求这个链接:open.weixin.qq.com/connect/qrconnect?appid=wx6ad144e54af67d87&redirect_uri=open.weixin.qq.com/connect/qrconnect?" + "appid=wx6ad144e54af67d87" + "&redirect_uri=blog.csdn.net/qq_42764468/article/details/107823201

版权声明:本文为CSDN博主「小小茶花女」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

近期热文推荐:

1.1,000+ 道 Java面试题及答案整理(2022最新版)

2.劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!

5.《Java开发手册(嵩山版)》最新发布,速速下载!

觉得不错,别忘了随手点赞+转发哦!

本文共计1695个文字,预计阅读时间需要7分钟。

Spring Boot如何轻松实现微信扫码登录,效果竟然如此惊艳?

微信开放平台:微信扫码登录功能+官方文档:https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.

1.授权流程说明:微信OAuth2.0授权登录,让微信用户安全登录

Spring Boot如何轻松实现微信扫码登录,效果竟然如此惊艳?

微信开放平台:微信扫码登录功能

官方文档:developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html

1. 授权流程说明

微信OAuth2.0授权登录让微信用户使用微信身份安全登录第三方应用或网站,在微信用户授权登录已接入微信OAuth2.0的第三方应用后,第三方可以获取到用户的接口调用凭证(access_token),通过access_token可以进行微信开放平台授权关系接口调用,从而可实现获取微信用户基本开放信息和帮助用户实现基础开放功能等。

微信OAuth2.0授权登录目前支持authorization_code模式,适用于拥有server端的应用授权。该模式整体流程为:

① 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据code参数;

② 通过code参数加上AppID和AppSecret等,通过API换取access_token;

③ 通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。

第一步:请求CODE

第三方使用网站应用授权登录前请注意已获取相应网页授权作用域(scope=snsapi_login),则可以通过在PC端打开以下链接:open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

返回说明

用户允许授权后,将会重定向到redirect_uri的网址上,并且带上code和state参数

redirect_uri?code=CODE&state=STATE

若用户禁止授权,则重定向后不会带上code参数,仅会带上state参数

redirect_uri?state=STATE

例如:登录一号店网站应用 passport.yhd.com/wechat/login.do 打开后,一号店会生成state参数,跳转到 open.weixin.qq.com/connect/qrconnect?appid=wxbdc5610cc59c1631&redirect_uri=passport.yhd.com/wechat/callback.do?code=CODE&state=3d6be0a4035d839573b04816624a415e

第二步:通过code获取access_token

通过code获取access_token

api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

返回说明

正确的返回:

{ "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE", "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL" }

错误返回样例:

{"errcode":40029,"errmsg":"invalid code"}

  • Appsecret 是应用接口使用密钥,泄漏后将可能导致应用数据泄漏、应用的用户数据泄漏等高风险后果;存储在客户端,极有可能被恶意窃取(如反编译获取Appsecret);
  • access_token 为用户授权第三方应用发起接口调用的凭证(相当于用户登录态),存储在客户端,可能出现恶意获取access_token 后导致的用户数据泄漏、用户微信相关接口功能被恶意发起等行为;
  • refresh_token 为用户授权第三方应用的长效凭证,仅用于刷新access_token,但泄漏后相当于access_token 泄漏,风险同上。

建议将secret、用户数据(如access_token)放在App云端服务器,由云端中转接口调用请求。

第三步:通过access_token调用接口

获取access_token后,进行接口调用,有以下前提:

  1. access_token有效且未超时;
  2. 微信用户已授权给第三方应用帐号相应接口作用域(scope)。

对于接口作用域(scope),能调用的接口有以下:

2. 授权流程代码

因为微信开放平台的AppiD和APPSecret和微信公众平台的AppiD和AppSecret都是不同的,因此需要配置一下:

# 开放平台 wechat.open-app-id=wx6ad144e54af67d87 wechat.open-app-secret=91a2ff6d38a2bbccfb7e9f9079108e2e @Data @Component @ConfigurationProperties(prefix = "wechat") public class WechatAccountConfig { //公众号appid private String mpAppId; //公众号appSecret private String mpAppSecret; //商户号 private String mchId; //商户秘钥 private String mchKey; //商户证书路径 private String keyPath; //微信支付异步通知 private String notifyUrl; //开放平台id private String openAppId; //开放平台秘钥 private String openAppSecret; } @Configuration public class WechatOpenConfig { @Autowired private WechatAccountConfig accountConfig; @Bean public WxMpService wxOpenService() { WxMpService wxOpenService = new WxMpServiceImpl(); wxOpenService.setWxMpConfigStorage(wxOpenConfigStorage()); return wxOpenService; } @Bean public WxMpConfigStorage wxOpenConfigStorage() { WxMpInMemoryConfigStorage wxMpInMemoryConfigStorage = new WxMpInMemoryConfigStorage(); wxMpInMemoryConfigStorage.setAppId(accountConfig.getOpenAppId()); wxMpInMemoryConfigStorage.setSecret(accountConfig.getOpenAppSecret()); return wxMpInMemoryConfigStorage; } } @Controller @RequestMapping("/wechat") @Slf4j public class WeChatController { @Autowired private WxMpService wxMpService; @Autowired private WxMpService wxOpenService; @GetMapping("/qrAuthorize") public String qrAuthorize() { //returnUrl就是用户授权同意后回调的地址 String returnUrl = "heng.nat300.top/sell/wechat/qrUserInfo"; //引导用户访问这个链接,进行授权 String url = wxOpenService.buildQrConnectUrl(returnUrl, WxConsts.QRCONNECT_SCOPE_SNSAPI_LOGIN, URLEncoder.encode(returnUrl)); return "redirect:" + url; } //用户授权同意后回调的地址,从请求参数中获取code @GetMapping("/qrUserInfo") public String qrUserInfo(@RequestParam("code") String code) { WxMpOAuth2AccessToken wxMpOAuth2AccessToken = new WxMpOAuth2AccessToken(); try { //通过code获取access_token wxMpOAuth2AccessToken = wxOpenService.oauth2getAccessToken(code); } catch (WxErrorException e) { log.error("{}", e); throw new SellException(ResultEnum.WECHAT_MP_ERROR.getCode(), e.getError().getErrorMsg()); } //从token中获取openid String openId = wxMpOAuth2AccessToken.getOpenId(); //这个地址可有可无,反正只是为了拿到openid,但是如果没有会报404错误,为了好看随便返回一个百度的地址 String returnUrl = "www.baidu.com"; log.info("openid={}", openId); return "redirect:" + returnUrl + "?openid="+openId; } }

请求路径:在浏览器打开

open.weixin.qq.com/connect/qrconnect?appid=wx6ad144e54af67d87&redirect_uri=heng.nat300.top/sell/seller/order/list"); } @GetMapping("/logout") public ModelAndView logout(HttpServletRequest request, HttpServletResponse response, Map<String, Object> map) { //1. 从cookie里查询 Cookie cookie = CookieUtil.get(request, CookieConstant.TOKEN); if (cookie != null) { //2. 清除redis redisTemplate.opsForValue().getOperations().delete(String.format(RedisConstant.TOKEN_PREFIX, cookie.getValue())); //3. 清除cookie CookieUtil.set(response, CookieConstant.TOKEN, null, 0); } map.put("msg", ResultEnum.LOGOUT_SUCCESS.getMessage()); map.put("url", "/sell/seller/order/list"); return new ModelAndView("common/success", map); } }

① 将上一步获取到的openid存入数据库

② 将授权后跳转的地址改为登录地址

//用户授权同意后回调的地址,从请求参数中获取code @GetMapping("/qrUserInfo") public String qrUserInfo(@RequestParam("code") String code) { WxMpOAuth2AccessToken wxMpOAuth2AccessToken = new WxMpOAuth2AccessToken(); try { //通过code获取access_token wxMpOAuth2AccessToken = wxOpenService.oauth2getAccessToken(code); } catch (WxErrorException e) { log.error("{}", e); throw new SellException(ResultEnum.WECHAT_MP_ERROR.getCode(), e.getError().getErrorMsg()); } //从token中获取openid String openId = wxMpOAuth2AccessToken.getOpenId(); //授权成功后跳转到卖家系统的登录地址 String returnUrl = "heng.nat300.top/sell/seller/login"; log.info("openid={}", openId); return "redirect:" + returnUrl + "?openid="+openId; }

③ 在浏览器请求这个链接:open.weixin.qq.com/connect/qrconnect?appid=wx6ad144e54af67d87&redirect_uri=open.weixin.qq.com/connect/qrconnect?" + "appid=wx6ad144e54af67d87" + "&redirect_uri=blog.csdn.net/qq_42764468/article/details/107823201

版权声明:本文为CSDN博主「小小茶花女」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

近期热文推荐:

1.1,000+ 道 Java面试题及答案整理(2022最新版)

2.劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!

5.《Java开发手册(嵩山版)》最新发布,速速下载!

觉得不错,别忘了随手点赞+转发哦!