<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          微信掃碼登錄很難嗎?5步幫你搞定

          共 10997字,需瀏覽 22分鐘

           ·

          2022-02-12 06:17

          來源丨java后端編程

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

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

          1. 授權(quán)流程說明

          微信OAuth2.0授權(quán)登錄讓微信用戶使用微信身份安全登錄第三方應(yīng)用或網(wǎng)站,在微信用戶授權(quán)登錄已接入微信OAuth2.0的第三方應(yīng)用后,第三方可以獲取到用戶的接口調(diào)用憑證(access_token),通過access_token可以進(jìn)行微信開放平臺(tái)授權(quán)關(guān)系接口調(diào)用,從而可實(shí)現(xiàn)獲取微信用戶基本開放信息和幫助用戶實(shí)現(xiàn)基礎(chǔ)開放功能等。

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

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

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

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

          第一步:請求CODE

          第三方使用網(wǎng)站應(yīng)用授權(quán)登錄前請注意已獲取相應(yīng)網(wǎng)頁授權(quán)作用域(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

          返回說明

          用戶允許授權(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

          例如:登錄一號店網(wǎng)站應(yīng)用?https://passport.yhd.com/wechat/login.do 打開后,一號店會(huì)生成state參數(shù),跳轉(zhuǎn)到 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?微信用戶使用微信掃描二維碼并且確認(rèn)登錄后,PC端會(huì)跳轉(zhuǎn)到?https://passport.yhd.com/wechat/callback.do?code=CODE&state=3d6be0a4035d839573b04816624a415e

          第二步:通過code獲取access_token

          通過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"
          }

          錯(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)用的長效憑證,僅用于刷新access_token,但泄漏后相當(dāng)于access_token 泄漏,風(fēng)險(xiǎn)同上。

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

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

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

          1. access_token有效且未超時(shí);

          2. 微信用戶已授權(quán)給第三方應(yīng)用帳號相應(yīng)接口作用域(scope)。

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

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

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

          #?開放平臺(tái)
          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;

          ????//開放平臺(tái)id
          ????private?String?openAppId;

          ????//開放平臺(tái)秘鑰
          ????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就是用戶授權(quán)同意后回調(diào)的地址
          ????????String?returnUrl?=?"http://heng.nat300.top/sell/wechat/qrUserInfo";

          ????????//引導(dǎo)用戶訪問這個(gè)鏈接,進(jìn)行授權(quán)
          ????????String?url?=?wxOpenService.buildQrConnectUrl(returnUrl,?WxConsts.QRCONNECT_SCOPE_SNSAPI_LOGIN,?URLEncoder.encode(returnUrl));
          ????????return?"redirect:"?+?url;
          ????}

          ????//用戶授權(quán)同意后回調(diào)的地址,從請求參數(shù)中獲取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("【微信網(wǎng)頁授權(quán)】{}",?e);
          ????????????throw?new?SellException(ResultEnum.WECHAT_MP_ERROR.getCode(),?e.getError().getErrorMsg());
          ????????}
          ????????//從token中獲取openid
          ????????String?openId?=?wxMpOAuth2AccessToken.getOpenId();

          ????????//這個(gè)地址可有可無,反正只是為了拿到openid,但是如果沒有會(huì)報(bào)404錯(cuò)誤,為了好看隨便返回一個(gè)百度的地址
          ????????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

          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?map)?{

          ????????//1.?openid去和數(shù)據(jù)庫里的數(shù)據(jù)匹配
          ????????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.?設(shè)置token至redis
          ????????String?token?=?UUID.randomUUID().toString();
          ????????//設(shè)置token的過期時(shí)間
          ????????Integer?expire?=?RedisConstant.EXPIRE;

          ????????redisTemplate.opsForValue().set(String.format(RedisConstant.TOKEN_PREFIX,?token),?openid,?expire,?TimeUnit.SECONDS);

          ????????//3.?設(shè)置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?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存入數(shù)據(jù)庫

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

          ?//用戶授權(quán)同意后回調(diào)的地址,從請求參數(shù)中獲取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("【微信網(wǎng)頁授權(quán)】{}",?e);
          ????????????throw?new?SellException(ResultEnum.WECHAT_MP_ERROR.getCode(),?e.getError().getErrorMsg());
          ????????}
          ????????//從token中獲取openid
          ????????String?openId?=?wxMpOAuth2AccessToken.getOpenId();

          ????????//授權(quán)成功后跳轉(zhuǎn)到賣家系統(tǒng)的登錄地址
          ????????String??returnUrl?=?"http://heng.nat300.top/sell/seller/login";

          ????????log.info("openid={}",?openId);

          ????????return?"redirect:"?+?returnUrl?+?"?openid="+openId;
          ????}

          ③ 在瀏覽器請求這個(gè)鏈接: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

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

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

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

          @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說明已經(jīng)登出或者根本沒有登錄
          ????????if?(cookie?==?null)?{
          ????????????log.warn("【登錄校驗(yàn)】Cookie中查不到token");
          ????????????//校驗(yàn)不通過,拋出異常
          ????????????throw?new?SellerAuthorizeException();
          ????????}

          ????????//去redis里查詢
          ????????String?tokenValue?=?redisTemplate.opsForValue().get(String.format(RedisConstant.TOKEN_PREFIX,?cookie.getValue()));
          ????????//如果redis中沒有對應(yīng)的openid,同樣表示登出或者根本沒有登錄
          ????????if?(StringUtils.isEmpty(tokenValue))?{
          ????????????log.warn("【登錄校驗(yàn)】Redis中查不到token");
          ????????????throw?new?SellerAuthorizeException();
          ????????}
          ????}
          }

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

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

          @ControllerAdvice
          public?class?SellExceptionHandler?{
          ????//攔截登錄異常
          ????@ExceptionHandler(value?=?SellerAuthorizeException.class) ????public?ModelAndView?handlerAuthorizeException()?{
          ????????//攔截異常后,跳轉(zhuǎn)到登錄界面
          ????????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()?{
          ????}
          }

          來源:hengheng.blog.csdn.net/article/details/107823201 ###

          -End-

          PS:如果覺得我的分享不錯(cuò),歡迎大家隨手點(diǎn)贊、在看。

          ?關(guān)注公眾號:Java后端編程,回復(fù)下面關(guān)鍵字?


          要Java學(xué)習(xí)完整路線,回復(fù)??路線?

          缺Java入門視頻,回復(fù)?視頻?

          要Java面試經(jīng)驗(yàn),回復(fù)??面試?

          缺Java項(xiàng)目,回復(fù):?項(xiàng)目?

          進(jìn)Java粉絲群:?加群?


          PS:如果覺得我的分享不錯(cuò),歡迎大家隨手點(diǎn)贊、在看。

          (完)




          加我"微信"?獲取一份 最新Java面試題資料

          請備注:666,不然不通過~


          最近好文


          1、再見了,收費(fèi)的XShell,我改用國產(chǎn)良心工具!

          2、給IDEA換個(gè)酷炫的主題,真的太好看了!

          3、SpringBoot快速開發(fā)利器:Spring Boot CLI

          4、基于SpringBoot 的CMS系統(tǒng),拿去開發(fā)企業(yè)官網(wǎng)

          5、本機(jī)號碼一鍵登錄原理與應(yīng)用



          最近面試BAT,整理一份面試資料Java面試BAT通關(guān)手冊,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)等等。
          獲取方式:關(guān)注公眾號并回復(fù)?java?領(lǐng)取,更多內(nèi)容陸續(xù)奉上。
          明天見(??ω??)??
          瀏覽 26
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  一本大道久久无码精品一区二区三区 | 男女操逼视频免费观看 | 777大香蕉 | 色逼成人综合一二三区 | www豆花视频 |