微信扫码登录 1. 授权流程说明第一步:请求 code第二步:通过 code 获取 access_token第三步:通过 access_token 调用接口 2. 授权流程代码3
微信 OAuth2.0授权登录让用户使用微信身份安全登录第三方应用或网站,在微信用户授权登录已接入微信 OAuth2.0的第三方应用后,第三方可以获取到用户的接口调用凭证(access_token),通过 access_token 可以进行微信开放平台授权关系接口调用,从而可实现获取微信用户基本开放信息和帮助用户实现基础开放开发功能等。
官方文档:https://developers.weixin.qq.com/doc/oplatfORM/WEBsite_App/WeChat_Login/Wechat_Login.html
微信OAuth2.0授权登录目前支持authorization_code模式,适用于拥有server端的应用授权。该模式整体流程为:
第三方使用网站应用授权登录前,需要注意已获取相应网页授权作用域(scope = snsapi_login),则可以通过在 PC端打开以下链接:记得替换成自己的参数
https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE
返回说明
用户允许授权后,将会重定向到 redirect_uri 的网址上,并带上 code 和 state 参数
redirect_uri?code=CODE&state=STATE
若用户禁止授权,则重定向后不会带上 code 参数,仅会带上 state 参数
redirect_uri?state=STATE
例如:
登录一号店网站应用:https://passport.yhd.com/wechat/login.do
打开后,一号店会生成 state 参数,跳转到 :
https://open.weixin.qq.com/connect/qrconnect?appid=wxbdc5610cc59c1631&redirect_uri=https%3A%2F%2Fpassport.yhd.com%2Fwechat%2Fcallback.do&response_type=code&scope=snsapi_login&state=3d6be0a4035d839573b04816624a415e#wechat_redirect
微信用户使用微信扫描二维码并且确认登录后,PC端会跳转到:https://passport.yhd.com/wechat/callback.do?code=CODE&state=3d6be0a4035d839573b04816624a415e
通过 code 获取 access_token
官方文档:Https://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"}
建议将 Secret、用户数据(如 access_token)放在App云端服务器,由云端中转接口调用请求。
获取access_token 后,进行接口调用,有以下前提:
access_token 有效且未超时;
2.微信用户已授权给第三方应用账号相应接口作用域(scope)
对于接口作用域(scope),能调用的接口有以下:
因为微信开放平台和微信公众平台的 AppID、AppSecret 都是不同的,因此需要配置以下:
# 开放平台wechat.open-app-id = wx6ad144e54af67d87wechat.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;}
@Configurationpublic 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")@Slf4jpublic class WeChatController { @Autowired private WxMpService wxMpService; @Autowired private WxMpService wxOpenService; @GetMapping("/qrAuthorize") public String qrAuthorize() { //returnUrl就是用户授权同意后回调的地址 String returnUrl = "http://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 = "http://www.baidu.com"; log.info("openid={}", openId); return "redirect:" + returnUrl + "?openid="+openId; }}
获取了openid:openid = o9AREv7Xr22ZUk6BtVqw82bb6AFk
@Controller@RequestMapping("/seller")public class SellerUserController { @Autowired private SellerService sellerService; @Autowired private StringRedisTemplate redisTemplate; @Autowired private ProjectUrlConfig projectUrlConfig; @GetMapping("/login") public ModelAndView login(@RequestParam("openid") String openid, HttpServletResponse response, Map<String, Object> map) { //1. openid去和数据库里的数据匹配 SellerInfo sellerInfo = sellerService.findSellerInfoByOpenid(openid); if (sellerInfo == null) { map.put("msg", ResultEnum.LOGIN_FAIL.getMessage()); map.put("url", "/sell/seller/order/list"); return new ModelAndView("common/error"); } //2. 设置token至redis String token = UUID.randomUUID().toString(); //设置token的过期时间 Integer expire = RedisConstant.EXPIRE; redisTemplate.opsForValue().set(String.format(RedisConstant.TOKEN_PREFIX, token), openid, expire, TimeUnit.SECONDS); //3. 设置token至cookie CookieUtil.set(response, CookieConstant.TOKEN, token, expire); return new ModelAndView("redirect:" + "http://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); }}
//用户授权同意后回调的地址,从请求参数中获取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 = "http://heng.nat300.top/sell/seller/login"; log.info("openid={}", openId); return "redirect:" + returnUrl + "?openid="+openId; }
@Aspect@Component@Slf4jpublic class SellerAuthorizeAspect { @Autowired private StringRedisTemplate redisTemplate; @Pointcut("execution(public * com.hh.controller.Seller*.*(..))" + "&& !execution(public * com.hh.controller.SellerUserController.*(..))") public void verify() {} @Before("verify()") public void doVerify() { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); //查询cookie Cookie cookie = CookieUtil.get(request, CookieConstant.TOKEN); //如果cookie中没有token说明已经登出或者根本没有登录 if (cookie == null) { log.warn("【登录校验】Cookie中查不到token"); //校验不通过,抛出异常 throw new SellerAuthorizeException(); } //去redis里查询 String tokenValue = redisTemplate.opsForValue().get(String.format(RedisConstant.TOKEN_PREFIX, cookie.getValue())); //如果redis中没有对应的openid,同样表示登出或者根本没有登录 if (StringUtils.isEmpty(tokenValue)) { log.warn("【登录校验】Redis中查不到token"); throw new SellerAuthorizeException(); } }}
拦截及登录校验不通过的异常,让其跳转的登录页面,扫码登录
@ControllerAdvicepublic class SellExceptionHandler { //拦截登录异常 @ExceptionHandler(value = SellerAuthorizeException.class) public ModelAndView handlerAuthorizeException() { //拦截异常后,跳转到登录界面 return new ModelAndView("redirect:".concat("https://open.weixin.qq.com/connect/qrconnect?" + "appid=wx6ad144e54af67d87" + "&redirect_uri=http%3A%2F%2Fsell.springboot.cn%2Fsell%2Fqr%2F" + "oTgZpwenC6lwO2eTDDf_-UYyFtqI" + "&response_type=code&scope=snsapi_login" + "&state=http%3a%2f%2fheng.nat300.top%2fsell%2fwechat%2fqrUserInfo")); } @ExceptionHandler(value = SellException.class) @ResponseBody public ResultVO handlerSellerException(SellException e) { return ResultVOUtil.error(e.getCode(), e.getMessage()); } @ExceptionHandler(value = ResponseBankException.class) @ResponseStatus(HttpStatus.FORBIDDEN) public void handleResponseBankException() {}}
好事定律:每件事最后都会是好事,如果不是好事,说明还没到最后。
来源地址:https://blog.csdn.net/Cike___/article/details/128901949
--结束END--
本文标题: Java实现微信扫码登录
本文链接: https://www.lsjlt.com/news/388060.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
下载Word文档到电脑,方便收藏和打印~
2024-04-03
2024-04-03
2024-04-01
2024-01-21
2024-01-21
2024-01-21
2024-01-21
2023-12-23
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0