微信開(kāi)放平臺(tái):微信掃碼登錄功能

正式文件:

1.批準(zhǔn)流程說(shuō)明

微信OAu認(rèn)證登錄允許微信用戶使用微信id安全登錄第三方應(yīng)用程序或網(wǎng)站,在微信用戶授權(quán)訪問(wèn)微信OAu的第三方應(yīng)用程序登錄后,第三方可以獲取用戶的接口調(diào)用憑證(access_token),通過(guò)ACESS _ TOKEN可以進(jìn)行微信開(kāi)放平臺(tái)認(rèn)證關(guān)系接口調(diào)用,從而獲得微信用戶的基本開(kāi)放信息

微信OAu授權(quán)登錄目前支持authorization_CODE模式,適用于擁有server端的應(yīng)用授權(quán)。該模式整體流程為:

① 第三方發(fā)起微信授權(quán)登錄請(qǐng)求,微信用戶允許授權(quán)第三方應(yīng)用后,微信會(huì)拉起應(yīng)用或重定向到第三方網(wǎng)站,并且?guī)鲜跈?quán)臨時(shí)票據(jù)code參數(shù);

② 通過(guò)code參數(shù)加上AppID和AppSecret等,通過(guò)API換取access_token;

③ 通過(guò)access_token進(jìn)行接口調(diào)用,獲取用戶基本數(shù)據(jù)資源或幫助用戶實(shí)現(xiàn)基本操作。

第一步:請(qǐng)求CODE

第三方使用網(wǎng)站應(yīng)用授權(quán)登錄前請(qǐng)注意已獲取相應(yīng)網(wǎng)頁(yè)授權(quán)作用域(scope=snsapi_login),則可以通過(guò)在PC端打開(kāi)以下鏈接:;redirect_uri=REDIRECT_URI&response_type=code&SCOPE=SCOPE&state=STATE#wechat_redirect

返回說(shuō)明

用戶允許授權(quán)后,將會(huì)重定向到redirect_uri的網(wǎng)址上,并且?guī)蟘ode和state參數(shù)

redirect_uri?code=CODE&state=STATE

若用戶禁止授權(quán),則重定向后不會(huì)帶上code參數(shù),僅會(huì)帶上state參數(shù)

redirect_uri?state=STATE

例如:登錄一號(hào)店網(wǎng)站應(yīng)用 打開(kāi)后,一號(hào)店會(huì)生成state參數(shù),跳轉(zhuǎn)到 ;redirect_uri=https%3A%2F%2F;response_type=code&scope=snsapi_login&state=3d6be0a4035d839573b04816624a415e#wechat_redirect 微信用戶使用微信掃描二維碼并且確認(rèn)登錄后,PC端會(huì)跳轉(zhuǎn)到 ;state=3d6be0a4035d839573b04816624a415e

第二步:通過(guò)code獲取access_token

通過(guò)code獲取access_token

;secret=SECRET&code=CODE&grant_type=authorization_code

返回說(shuō)明

正確的返回:

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

錯(cuò)誤返回樣例:

{"errcode":40029,"errmsg":"invalid code"}
  • Appsecret 是應(yīng)用接口使用密鑰,泄漏后將可能導(dǎo)致應(yīng)用數(shù)據(jù)泄漏、應(yīng)用的用戶數(shù)據(jù)泄漏等高風(fēng)險(xiǎn)后果;存儲(chǔ)在客戶端,極有可能被惡意竊?。ㄈ绶淳幾g獲取Appsecret);
  • access_token 為用戶授權(quán)第三方應(yīng)用發(fā)起接口調(diào)用的憑證(相當(dāng)于用戶登錄態(tài)),存儲(chǔ)在客戶端,可能出現(xiàn)惡意獲取access_token 后導(dǎo)致的用戶數(shù)據(jù)泄漏、用戶微信相關(guān)接口功能被惡意發(fā)起等行為;
  • refresh_token 為用戶授權(quán)第三方應(yīng)用的長(zhǎng)效憑證,僅用于刷新access_token,但泄漏后相當(dāng)于access_token 泄漏,風(fēng)險(xiǎn)同上。

建議將secret、用戶數(shù)據(jù)(如access_token)放在App云端服務(wù)器,由云端中轉(zhuǎn)接口調(diào)用請(qǐng)求。

第三步:通過(guò)access_token調(diào)用接口

獲取access_token后,進(jìn)行接口調(diào)用,有以下前提:

  1. access_token有效且未超時(shí);
  2. 微信用戶已授權(quán)給第三方應(yīng)用帳號(hào)相應(yīng)接口作用域(scope)。

對(duì)于接口作用域(scope),能調(diào)用的接口有以下:


2. 授權(quán)流程代碼

因?yàn)槲⑿砰_(kāi)放平臺(tái)的AppiD和APPSecret和微信公眾平臺(tái)的AppiD和AppSecret都是不同的,因此需要配置一下:

# 開(kāi)放平臺(tái) wec wec @Data @Component @ConfigurationProperties(prefix = "wechat") public class WechatAccountConfig { //公眾號(hào)appid private String mpAppId; //公眾號(hào)appSecret private String mpAppSecret; //商戶號(hào) private String mchId; //商戶秘鑰 private String mchKey; //商戶證書(shū)路徑 private String keyPath; //微信支付異步通知 private String notifyUrl; //開(kāi)放平臺(tái)id private String openAppId; //開(kāi)放平臺(tái)秘鑰 private String openAppSecret; } @Configuration public class WechatOpenConfig { @Autowired private WechatAccountConfig accountConfig; @Bean public WxMpService wxOpenService() { WxMpService wxOpenService = new WxMpServiceImpl(); wxO(wxOpenConfigStorage()); return wxOpenService; } @Bean public WxMpConfigStorage wxOpenConfigStorage() { WxMpInMemoryConfigStorage wxMpInMemoryConfigStorage = new WxMpInMemoryConfigStorage(); wxM()); wxM()); return wxMpInMemoryConfigStorage; } } @Controller @RequestMapping("/wechat") @Slf4j public class WeChatController { @Autowired private WxMpService wxMpService; @Autowired private WxMpService wxOpenService; @GetMapping("/qrAuthorize") public String qrAuthorize() { //returnUrl就是用戶授權(quán)同意后回調(diào)的地址 String returnUrl = ";; //引導(dǎo)用戶訪問(wèn)這個(gè)鏈接,進(jìn)行授權(quán) String url = wxO(returnUrl, WxCon, URLEncoder.encode(returnUrl)); return "redirect:" + url; } //用戶授權(quán)同意后回調(diào)的地址,從請(qǐng)求參數(shù)中獲取code @GetMapping("/qrUserInfo") public String qrUserInfo(@RequestParam("code") String code) { WxMpOAuth2AccessToken wxMpOAuth2AccessToken = new WxMpOAuth2AccessToken(); try { //通過(guò)code獲取access_token wxMpOAuth2AccessToken = wxO(code); } catch (WxErrorException e) { log.error("【微信網(wǎng)頁(yè)授權(quán)】{}", e); throw new SellException(), e.getError().getErrorMsg()); } //從token中獲取openid String openId = wxM(); //這個(gè)地址可有可無(wú),反正只是為了拿到openid,但是如果沒(méi)有會(huì)報(bào)404錯(cuò)誤,為了好看隨便返回一個(gè)百度的地址 String returnUrl = ";; log.info("openid={}", openId); return "redirect:" + returnUrl + "?openid="+openId; } }

請(qǐng)求路徑:在瀏覽器打開(kāi)

;redirect_uri=http%3A%2F%2F;response_type=code&scope=snsapi_login&state=http%3a%2f%2

獲取了openid:openid=o9AREv7Xr22ZUk6BtVqw82bb6AFk


3. 用戶登錄和登出

@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去和數(shù)據(jù)庫(kù)里的數(shù)據(jù)匹配 SellerInfo sellerInfo = (openid); if (sellerInfo == null) { map.put("msg", Re()); map.put("url", "/sell/seller/order/list"); return new ModelAndView("common/error"); } //2. 設(shè)置token至redis String token = UUID.randomUUID().toString(); //設(shè)置token的過(guò)期時(shí)間 Integer expire = Redi; redi().se, token), openid, expire, TimeUnit.SECONDS); //3. 設(shè)置token至cookie CookieU(response, CookieCon, token, expire); return new ModelAndView("redirect:" + ";); } @GetMapping("/logout") public ModelAndView logout(HttpServletRequest request, HttpServletResponse response, Map<String, Object> map) { //1. 從cookie里查詢 Cookie cookie = CookieU(request, CookieCon); if (cookie != null) { //2. 清除Redis redi().getOperations().delete, cookie.getValue())); //3. 清除cookie CookieU(response, CookieCon, null, 0); } map.put("msg", Re()); map.put("url", "/sell/seller/order/list"); return new ModelAndView("common/success", map); } }

① 將上一步獲取到的openid存入數(shù)據(jù)庫(kù)

② 將授權(quán)后跳轉(zhuǎn)的地址改為登錄地址

//用戶授權(quán)同意后回調(diào)的地址,從請(qǐng)求參數(shù)中獲取code @GetMapping("/qrUserInfo") public String qrUserInfo(@RequestParam("code") String code) { WxMpOAuth2AccessToken wxMpOAuth2AccessToken = new WxMpOAuth2AccessToken(); try { //通過(guò)code獲取access_token wxMpOAuth2AccessToken = wxO(code); } catch (WxErrorException e) { log.error("【微信網(wǎng)頁(yè)授權(quán)】{}", e); throw new SellException(), e.getError().getErrorMsg()); } //從token中獲取openid String openId = wxM(); //授權(quán)成功后跳轉(zhuǎn)到賣(mài)家系統(tǒng)的登錄地址 String returnUrl = ";; log.info("openid={}", openId); return "redirect:" + returnUrl + "?openid="+openId; }

③ 在瀏覽器請(qǐng)求這個(gè)鏈接:;redirect_uri=http%3A%2F%2F;response_type=code&scope=snsapi_login&state=http%3a%2f%2

第三應(yīng)用請(qǐng)求使用微信掃碼登錄,而不是使用本網(wǎng)站的密碼:

用戶同意授權(quán)后登入第三方應(yīng)用的后臺(tái)管理系統(tǒng):

4. Spring AOP校驗(yàn)用戶有沒(méi)有登錄

@Aspect @Component @Slf4j public class SellerAuthorizeAspect { @Autowired private StringRedisTemplate redisTemplate; @Pointcut("execution(public * com.*.*(..))" + "&& !execution(public * com.UserController.*(..))") public void verify() {} @Before("verify()") public void doVerify() { ServletRequestAttributes attributes = (ServletRequestAttributes) Reque(); HttpServletRequest request = a(); //查詢cookie Cookie cookie = CookieU(request, CookieCon); //如果cookie中沒(méi)有token說(shuō)明已經(jīng)登出或者根本沒(méi)有登錄 if (cookie == null) { log.warn("【登錄校驗(yàn)】Cookie中查不到token"); //校驗(yàn)不通過(guò),拋出異常 throw new SellerAuthorizeException(); } //去redis里查詢 String tokenValue = redi().ge, cookie.getValue())); //如果redis中沒(méi)有對(duì)應(yīng)的openid,同樣表示登出或者根本沒(méi)有登錄 if (tokenValue)) { log.warn("【登錄校驗(yàn)】Redis中查不到token"); throw new SellerAuthorizeException(); } } }


5. 攔截登錄校驗(yàn)不通過(guò)拋出的異常

攔截及登錄校驗(yàn)不通過(guò)的異常,讓其跳轉(zhuǎn)到登錄頁(yè)面,掃碼登錄

@ControllerAdvice public class SellExceptionHandler { //攔截登錄異常 @ExceptionHandler(value = SellerAu) public ModelAndView handlerAuthorizeException() { //攔截異常后,跳轉(zhuǎn)到登錄界面 return new ModelAndView("redirect:".concat("; + "appid=wx6ad144e54af67d87" + "&redirect_uri=http%3A%2F%2F; + "oTgZpwenC6lwO2eTDDf_-UYyFtqI" + "&response_type=code&scope=snsapi_login" + "&state=http%3a%2f%2")); } @ExceptionHandler(value = SellExce) @ResponseBody public ResultVO handlerSellerException(SellException e) { return Re(), e.getMessage()); } @ExceptionHandler(value = ResponseBankExce) @ResponseStatu) public void handleResponseBankException() { } }

來(lái)源:

1.《微信怎么用二維碼登陸不了看這里!微信掃碼登錄很難嗎?5步幫你搞定》援引自互聯(lián)網(wǎng),旨在傳遞更多網(wǎng)絡(luò)信息知識(shí),僅代表作者本人觀點(diǎn),與本網(wǎng)站無(wú)關(guān),侵刪請(qǐng)聯(lián)系頁(yè)腳下方聯(lián)系方式。

2.《微信怎么用二維碼登陸不了看這里!微信掃碼登錄很難嗎?5步幫你搞定》僅供讀者參考,本網(wǎng)站未對(duì)該內(nèi)容進(jìn)行證實(shí),對(duì)其原創(chuàng)性、真實(shí)性、完整性、及時(shí)性不作任何保證。

3.文章轉(zhuǎn)載時(shí)請(qǐng)保留本站內(nèi)容來(lái)源地址,http://f99ss.com/gl/2975813.html