Spring Boot怎么实现微信扫码登录功能
导读:本文共6995.5字符,通常情况下阅读需要23分钟。同时您也可以点击右侧朗读,来听本文内容。按键盘←(左) →(右) 方向键可以翻页。
摘要: 1. 授权流程说明微信OAuth4.0授权登录让微信用户使用微信身份安全登录第三方应用或网站,在微信用户授权登录已接入微信OAuth4.0的第三方应用后,第三方可以获取到用户的接口调用凭证(access_token),通过access_token可以进行微信开放平台授权关系接口调用,从而可实现获取微信用户基本开放信息和帮助用户实现基础开放功能等。微信OAuth4... ...
目录
(为您整理了一些要点),点击可以直达。1. 授权流程说明
微信OAuth4.0授权登录让微信用户使用微信身份安全登录第三方应用或网站,在微信用户授权登录已接入微信OAuth4.0的第三方应用后,第三方可以获取到用户的接口调用凭证(access_token),通过access_token可以进行微信开放平台授权关系接口调用,从而可实现获取微信用户基本开放信息和帮助用户实现基础开放功能等。
微信OAuth4.0授权登录目前支持authorization_code模式,适用于拥有server端的应用授权。该模式整体流程为:
① 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据code参数;
② 通过code参数加上AppID和AppSecret等,通过API换取access_token;
③ 通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。
第一步:请求CODE
第三方使用网站应用授权登录前请注意已获取相应网页授权作用域(scope=snsapi_login),则可以通过在PC端打开以下链接:https://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
例如:登录一号店网站应用 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
通过code获取access_token
https://api.weixin.qq.com/sns/oauth4/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":"invalidcode"}
Appsecret 是应用接口使用密钥,泄漏后将可能导致应用数据泄漏、应用的用户数据泄漏等高风险后果;存储在客户端,极有可能被恶意窃取(如反编译获取Appsecret);
access_token 为用户授权第三方应用发起接口调用的凭证(相当于用户登录态),存储在客户端,可能出现恶意获取access_token 后导致的用户数据泄漏、用户微信相关接口功能被恶意发起等行为;
refresh_token 为用户授权第三方应用的长效凭证,仅用于刷新access_token,但泄漏后相当于access_token 泄漏,风险同上。
建议将secret、用户数据(如access_token)放在App云端服务器,由云端中转接口调用请求。
第三步:通过access_token调用接口
获取access_token后,进行接口调用,有以下前提:
access_token有效且未超时;
微信用户已授权给第三方应用帐号相应接口作用域(scope)。
对于接口作用域(scope),能调用的接口有以下:
2. 授权流程代码
因为微信开放平台的AppiD和APPSecret和微信公众平台的AppiD和AppSecret都是不同的,因此需要配置一下:
#开放平台wechat.open-app-id=wx6ad144e54af67d87wechat.open-app-secret=91a2ff6d38a2bbccfb7e9f9079108e2e@Data@Component@ConfigurationProperties(prefix="wechat")publicclassWechatAccountConfig{//公众号appidprivateStringmpAppId;//公众号appSecretprivateStringmpAppSecret;//商户号privateStringmchId;//商户秘钥privateStringmchKey;//商户证书路径privateStringkeyPath;//微信支付异步通知privateStringnotifyUrl;//开放平台idprivateStringopenAppId;//开放平台秘钥privateStringopenAppSecret;}@ConfigurationpublicclassWechatOpenConfig{@AutowiredprivateWechatAccountConfigaccountConfig;@BeanpublicWxMpServicewxOpenService(){WxMpServicewxOpenService=newWxMpServiceImpl();wxOpenService.setWxMpConfigStorage(wxOpenConfigStorage());returnwxOpenService;}publicWxMpConfigStoragewxOpenConfigStorage(){WxMpInMemoryConfigStoragewxMpInMemoryConfigStorage=newWxMpInMemoryConfigStorage();wxMpInMemoryConfigStorage.setAppId(accountConfig.getOpenAppId());wxMpInMemoryConfigStorage.setSecret(accountConfig.getOpenAppSecret());returnwxMpInMemoryConfigStorage;@Controller@RequestMapping("/wechat")@Slf4jpublicclassWeChatController{privateWxMpServicewxMpService;privateWxMpServicewxOpenService;@GetMapping("/qrAuthorize")publicStringqrAuthorize(){//returnUrl就是用户授权同意后回调的地址StringreturnUrl="http://heng.nat300.top/sell/wechat/qrUserInfo";//引导用户访问这个链接,进行授权Stringurl=wxOpenService.buildQrConnectUrl(returnUrl,WxConsts.QRCONNECT_SCOPE_SNSAPI_LOGIN,URLEncoder.encode(returnUrl));return"redirect:"+url;//用户授权同意后回调的地址,从请求参数中获取code@GetMapping("/qrUserInfo")publicStringqrUserInfo(@RequestParam("code")Stringcode){WxMpOAuth4AccessTokenwxMpOAuth4AccessToken=newWxMpOAuth4AccessToken();try{//通过code获取access_tokenwxMpOAuth4AccessToken=wxOpenService.oauth4getAccessToken(code);}catch(WxErrorExceptione){log.error("【微信网页授权】{}",e);thrownewSellException(ResultEnum.WECHAT_MP_ERROR.getCode(),e.getError().getErrorMsg());}//从token中获取openidStringopenId=wxMpOAuth4AccessToken.getOpenId();//这个地址可有可无,反正只是为了拿到openid,但是如果没有会报404错误,为了好看随便返回一个百度的地址StringreturnUrl="http://www.baidu.com";log.info("openid={}",openId);return"redirect:"+returnUrl+"?openid="+openId;
请求路径:在浏览器打开
https://open.weixin.qq.com/connect/qrconnect?appid=wx6ad144e54af67d87&redirect_uri=http%3A%2F%2Fsell.springboot.cn%2Fsell%2Fqr%2FoTgZpwenC6lwO2eTDDf_-UYyFtqI&response_type=code&scope=snsapi_login&state=http%3A%2F%2Fheng.nat300.top%2Fsell%2Fwechat%2FqrUserInfo
获取了openid:openid=o9AREv7Xr22ZUk6BtVqw82bb6AFk
3. 用户登录和登出
@Controller@RequestMapping("/seller")publicclassSellerUserController{@AutowiredprivateSellerServicesellerService;privateStringRedisTemplateredisTemplate;privateProjectUrlConfigprojectUrlConfig;@GetMapping("/login")publicModelAndViewlogin(@RequestParam("openid")Stringopenid,HttpServletResponseresponse,Map<String,Object>map){//1.openid去和数据库里的数据匹配SellerInfosellerInfo=sellerService.findSellerInfoByOpenid(openid);if(sellerInfo==null){map.put("msg",ResultEnum.LOGIN_FAIL.getMessage());map.put("url","/sell/seller/order/list");returnnewModelAndView("common/error");}//2.设置token至redisStringtoken=UUID.randomUUID().toString();//设置token的过期时间Integerexpire=RedisConstant.EXPIRE;redisTemplate.opsForValue().set(String.format(RedisConstant.TOKEN_PREFIX,token),openid,expire,TimeUnit.SECONDS);//3.设置token至cookieCookieUtil.set(response,CookieConstant.TOKEN,token,expire);returnnewModelAndView("redirect:"+"http://heng.nat300.top/sell/seller/order/list");}@GetMapping("/logout")publicModelAndViewlogout(HttpServletRequestrequest,HttpServletResponseresponse,Map<String,Object>map){//1.从cookie里查询Cookiecookie=CookieUtil.get(request,CookieConstant.TOKEN);if(cookie!=null){//2.清除redisredisTemplate.opsForValue().getOperations().delete(String.format(RedisConstant.TOKEN_PREFIX,cookie.getValue()));//3.清除cookieCookieUtil.set(response,CookieConstant.TOKEN,null,0);map.put("msg",ResultEnum.LOGOUT_SUCCESS.getMessage());map.put("url","/sell/seller/order/list");returnnewModelAndView("common/success",map);}
① 将上一步获取到的openid存入数据库
② 将授权后跳转的地址改为登录地址
//用户授权同意后回调的地址,从请求参数中获取code@GetMapping("/qrUserInfo")publicStringqrUserInfo(@RequestParam("code")Stringcode){WxMpOAuth4AccessTokenwxMpOAuth4AccessToken=newWxMpOAuth4AccessToken();try{//通过code获取access_tokenwxMpOAuth4AccessToken=wxOpenService.oauth4getAccessToken(code);}catch(WxErrorExceptione){log.error("【微信网页授权】{}",e);thrownewSellException(ResultEnum.WECHAT_MP_ERROR.getCode(),e.getError().getErrorMsg());}//从token中获取openidStringopenId=wxMpOAuth4AccessToken.getOpenId();//授权成功后跳转到卖家系统的登录地址StringreturnUrl="http://heng.nat300.top/sell/seller/login";log.info("openid={}",openId);return"redirect:"+returnUrl+"?openid="+openId;}
③ 在浏览器请求这个链接:
https://open.weixin.qq.com/connect/qrconnect?appid=wx6ad144e54af67d87&redirect_uri=http%3A%2F%2Fsell.springboot.cn%2Fsell%2Fqr%2FoTgZpwenC6lwO2eTDDf_-UYyFtqI&response_type=code&scope=snsapi_login&state=http%3a%2f%2fheng.nat300.top%2fsell%2fwechat%2fqrUserInfo
第三应用请求使用微信扫码登录,而不是使用本网站的密码:
用户同意授权后登入第三方应用的后台管理系统:
4. Spring AOP校验用户有没有登录
@Aspect@Component@Slf4jpublicclassSellerAuthorizeAspect{@AutowiredprivateStringRedisTemplateredisTemplate;@Pointcut("execution(public*com.hh.controller.Seller*.*(..))"+"&&!execution(public*com.hh.controller.SellerUserController.*(..))")publicvoidverify(){}@Before("verify()")publicvoiddoVerify(){ServletRequestAttributesattributes=(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();HttpServletRequestrequest=attributes.getRequest();//查询cookieCookiecookie=CookieUtil.get(request,CookieConstant.TOKEN);//如果cookie中没有token说明已经登出或者根本没有登录if(cookie==null){log.warn("【登录校验】Cookie中查不到token");//校验不通过,抛出异常thrownewSellerAuthorizeException();}//去redis里查询StringtokenValue=redisTemplate.opsForValue().get(String.format(RedisConstant.TOKEN_PREFIX,cookie.getValue()));//如果redis中没有对应的openid,同样表示登出或者根本没有登录if(StringUtils.isEmpty(tokenValue)){log.warn("【登录校验】Redis中查不到token");}}
5. 拦截登录校验不通过抛出的异常
拦截及登录校验不通过的异常,让其跳转到登录页面,扫码登录
@ControllerAdvicepublicclassSellExceptionHandler{//拦截登录异常@ExceptionHandler(value=SellerAuthorizeException.class)publicModelAndViewhandlerAuthorizeException(){//拦截异常后,跳转到登录界面returnnewModelAndView("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)@ResponseBodypublicResultVOhandlerSellerException(SellExceptione){returnResultVOUtil.error(e.getCode(),e.getMessage());}@ExceptionHandler(value=ResponseBankException.class)@ResponseStatus(HttpStatus.FORBIDDEN)publicvoidhandleResponseBankException(){}}
</div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
Spring Boot怎么实现微信扫码登录功能的详细内容,希望对您有所帮助,信息来源于网络。