您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“Spring Boot怎么實現微信掃碼登錄功能”,內容詳細,步驟清晰,細節處理妥當,希望這篇“Spring Boot怎么實現微信掃碼登錄功能”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
微信OAuth4.0授權登錄讓微信用戶使用微信身份安全登錄第三方應用或網站,在微信用戶授權登錄已接入微信OAuth4.0的第三方應用后,第三方可以獲取到用戶的接口調用憑證(access_token),通過access_token可以進行微信開放平臺授權關系接口調用,從而可實現獲取微信用戶基本開放信息和幫助用戶實現基礎開放功能等。
微信OAuth4.0授權登錄目前支持authorization_code模式,適用于擁有server端的應用授權。該模式整體流程為:
① 第三方發起微信授權登錄請求,微信用戶允許授權第三方應用后,微信會拉起應用或重定向到第三方網站,并且帶上授權臨時票據code參數;
② 通過code參數加上AppID和AppSecret等,通過API換取access_token;
③ 通過access_token進行接口調用,獲取用戶基本數據資源或幫助用戶實現基本操作。
第三方使用網站應用授權登錄前請注意已獲取相應網頁授權作用域(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
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":"invalid code"}
Appsecret 是應用接口使用密鑰,泄漏后將可能導致應用數據泄漏、應用的用戶數據泄漏等高風險后果;存儲在客戶端,極有可能被惡意竊取(如反編譯獲取Appsecret);
access_token 為用戶授權第三方應用發起接口調用的憑證(相當于用戶登錄態),存儲在客戶端,可能出現惡意獲取access_token 后導致的用戶數據泄漏、用戶微信相關接口功能被惡意發起等行為;
refresh_token 為用戶授權第三方應用的長效憑證,僅用于刷新access_token,但泄漏后相當于access_token 泄漏,風險同上。
建議將secret、用戶數據(如access_token)放在App云端服務器,由云端中轉接口調用請求。
獲取access_token后,進行接口調用,有以下前提:
access_token有效且未超時;
微信用戶已授權給第三方應用帳號相應接口作用域(scope)。
對于接口作用域(scope),能調用的接口有以下:
因為微信開放平臺的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; } public WxMpConfigStorage wxOpenConfigStorage() { WxMpInMemoryConfigStorage wxMpInMemoryConfigStorage = new WxMpInMemoryConfigStorage(); wxMpInMemoryConfigStorage.setAppId(accountConfig.getOpenAppId()); wxMpInMemoryConfigStorage.setSecret(accountConfig.getOpenAppSecret()); return wxMpInMemoryConfigStorage; @Controller @RequestMapping("/wechat") @Slf4j public class WeChatController { private WxMpService wxMpService; 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) { WxMpOAuth4AccessToken wxMpOAuth4AccessToken = new WxMpOAuth4AccessToken(); try { //通過code獲取access_token wxMpOAuth4AccessToken = wxOpenService.oauth4getAccessToken(code); } catch (WxErrorException e) { log.error("【微信網頁授權】{}", e); throw new SellException(ResultEnum.WECHAT_MP_ERROR.getCode(), e.getError().getErrorMsg()); } //從token中獲取openid String openId = wxMpOAuth4AccessToken.getOpenId(); //這個地址可有可無,反正只是為了拿到openid,但是如果沒有會報404錯誤,為了好看隨便返回一個百度的地址 String returnUrl = "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
@Controller @RequestMapping("/seller") public class SellerUserController { @Autowired private SellerService sellerService; private StringRedisTemplate redisTemplate; 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); }
① 將上一步獲取到的openid存入數據庫
② 將授權后跳轉的地址改為登錄地址
//用戶授權同意后回調的地址,從請求參數中獲取code @GetMapping("/qrUserInfo") public String qrUserInfo(@RequestParam("code") String code) { WxMpOAuth4AccessToken wxMpOAuth4AccessToken = new WxMpOAuth4AccessToken(); try { //通過code獲取access_token wxMpOAuth4AccessToken = wxOpenService.oauth4getAccessToken(code); } catch (WxErrorException e) { log.error("【微信網頁授權】{}", e); throw new SellException(ResultEnum.WECHAT_MP_ERROR.getCode(), e.getError().getErrorMsg()); } //從token中獲取openid String openId = wxMpOAuth4AccessToken.getOpenId(); //授權成功后跳轉到賣家系統的登錄地址 String returnUrl = "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
第三應用請求使用微信掃碼登錄,而不是使用本網站的密碼:
用戶同意授權后登入第三方應用的后臺管理系統:
@Aspect @Component @Slf4j public 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"); } }
攔截及登錄校驗不通過的異常,讓其跳轉到登錄頁面,掃碼登錄
@ControllerAdvice public 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() { } }
讀到這里,這篇“Spring Boot怎么實現微信掃碼登錄功能”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。