<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步幫你搞定

          共 18385字,需瀏覽 37分鐘

           ·

          2021-12-26 00:34

          微信開放平臺:微信掃碼登錄功能

          官方文檔: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可以進行微信開放平臺授權(quán)關(guān)系接口調(diào)用,從而可實現(xiàn)獲取微信用戶基本開放信息和幫助用戶實現(xiàn)基礎(chǔ)開放功能等。

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

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

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

          ③ 通過access_token進行接口調(diào)用,獲取用戶基本數(shù)據(jù)資源或幫助用戶實現(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)后,將會重定向到redirect_uri的網(wǎng)址上,并且?guī)蟘ode和state參數(shù)

          redirect_uri?code=CODE&state=STATE

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

          redirect_uri?state=STATE

          例如:登錄一號店網(wǎng)站應(yīng)用 https://passport.yhd.com/wechat/login.do 打開后,一號店會生成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 微信用戶使用微信掃描二維碼并且確認登錄后,PC端會跳轉(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"
          }

          錯誤返回樣例:

          {"errcode":40029,"errmsg":"invalid code"}
          • Appsecret 是應(yīng)用接口使用密鑰,泄漏后將可能導(dǎo)致應(yīng)用數(shù)據(jù)泄漏、應(yīng)用的用戶數(shù)據(jù)泄漏等高風險后果;存儲在客戶端,極有可能被惡意竊?。ㄈ绶淳幾g獲取Appsecret);

          • access_token 為用戶授權(quán)第三方應(yīng)用發(fā)起接口調(diào)用的憑證(相當于用戶登錄態(tài)),存儲在客戶端,可能出現(xiàn)惡意獲取access_token 后導(dǎo)致的用戶數(shù)據(jù)泄漏、用戶微信相關(guān)接口功能被惡意發(fā)起等行為;

          • refresh_token 為用戶授權(quán)第三方應(yīng)用的長效憑證,僅用于刷新access_token,但泄漏后相當于access_token 泄漏,風險同上。

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

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

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

          1. access_token有效且未超時;

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

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

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

          因為微信開放平臺的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;
              }

              @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)用戶訪問這個鏈接,進行授權(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();

                  //這個地址可有可無,反正只是為了拿到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

          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ù)庫里的數(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的過期時間
                  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<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, null0);
                  }

                  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;
              }

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

          4. Spring AOP校驗用戶有沒有登錄

          @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("【登錄校驗】Cookie中查不到token");
                      //校驗不通過,拋出異常
                      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("【登錄校驗】Redis中查不到token");
                      throw new SellerAuthorizeException();
                  }
              }
          }

          5. 攔截登錄校驗不通過拋出的異常

          攔截及登錄校驗不通過的異常,讓其跳轉(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 ###


          怎么接私活?這個渠道你100%有用!請收藏!


          在看 
          瀏覽 83
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  国产精品久久久久久久免费大片 | 翔田千里久久一区二区 | 免费看h网站 | 插进去综合网 | 超碰成人一区二区三区 |