sponsored links

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

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

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

1. 授權流程說明

微信OAuth2.0授權登入讓微信使用者使用微信身份安全登入第三方應用或網站,在微信使用者授權登入已接入微信OAuth2.0的第三方應用後,第三方可以獲取到使用者的介面呼叫憑證(access_token),透過access_token可以進行微信開放平臺授權關係介面呼叫,從而可實現獲取微信使用者基本開放資訊和幫助使用者實現基礎開放功能等。

微信OAuth2.0授權登入目前支援authorization_code模式,適用於擁有server端的應用授權。該模式整體流程為:

① 第三方發起微信授權登入請求,微信使用者允許授權第三方應用後,微信會拉起應用或重定向到第三方網站,並且帶上授權臨時票據code引數;

② 透過code引數加上AppID和AppSecret等,透過API換取access_token;

③ 透過access_token進行介面呼叫,獲取使用者基本資料資源或幫助使用者實現基本操作。

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

第一步:請求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/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 是應用介面使用金鑰,洩漏後將可能導致應用資料洩漏、應用的使用者資料洩漏等高風險後果;儲存在客戶端,極有可能被惡意竊取(如反編譯獲取Appsecret);
  • access_token 為使用者授權第三方應用發起介面呼叫的憑證(相當於使用者登入態),儲存在客戶端,可能出現惡意獲取access_token 後導致的使用者資料洩漏、使用者微信相關介面功能被惡意發起等行為;
  • refresh_token 為使用者授權第三方應用的長效憑證,僅用於重新整理access_token,但洩漏後相當於access_token 洩漏,風險同上。

建議將secret、使用者資料(如access_token)放在App雲端伺服器,由雲端中轉介面呼叫請求。

第三步:透過access_token呼叫介面

獲取access_token後,進行介面呼叫,有以下前提:

  1. access_token有效且未超時;
  2. 微信使用者已授權給第三方應用帳號相應介面作用域(scope)。

對於介面作用域(scope),能呼叫的介面有以下:

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

2. 授權流程程式碼

因為微信開放平臺的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就是使用者授權同意後回撥的地址
        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) {
        WxMpOAuth2AccessToken wxMpOAuth2AccessToken = new WxMpOAuth2AccessToken();
        try {
            //透過code獲取access_token
            wxMpOAuth2AccessToken = wxOpenService.oauth2getAccessToken(code);
        } catch (WxErrorException e) {
            log.error("【微信網頁授權】{}", 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

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

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去和資料庫裡的資料匹配
        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存入資料庫

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

② 將授權後跳轉的地址改為登入地址

 //使用者授權同意後回撥的地址,從請求引數中獲取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("【微信網頁授權】{}", e);
            throw new SellException(ResultEnum.WECHAT_MP_ERROR.getCode(), e.getError().getErrorMsg());
        }
        //從token中獲取openid
        String openId = wxMpOAuth2AccessToken.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

第三應用請求使用微信掃碼登入,而不是使用本網站的密碼:

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

使用者同意授權後登入第三方應用的後臺管理系統:

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

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

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說明已經登出或者根本沒有登入
        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");
            throw new SellerAuthorizeException();
        }
    }
}

5. 攔截登入校驗不透過丟擲的異常

攔截及登入校驗不透過的異常,讓其跳轉到登入頁面,掃碼登入

@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() {
    }
}

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

分類: 軍事
時間: 2021-12-22

相關文章

蘇錫常富裕水平到底超過多少歐洲國家?

蘇錫常富裕水平到底超過多少歐洲國家?
所謂蘇錫常,就是傳統意義上的蘇南,特是指蘇州.無錫.常州三個市,簡稱蘇錫常.自1951年至1953年,曾由江蘇省的蘇南行政區統一管轄.以長江和淮河為界,江蘇省分蘇南.蘇中.蘇北三個部分,區域經濟發展的 ...

歐洲國家的國旗,為什麼很多都是“三色旗”?

歐洲國家的國旗,為什麼很多都是“三色旗”?
2021年8月8日晚的東京奧運會閉幕式上,204個國家和地區的選手代表高舉著本國或本地區的旗幟緩緩入場,使東京新國立競技場變成了一片國旗的海洋. ▲奧運會閉幕式是國旗的海洋 細心的觀眾一定已經發現,不 ...

盤點歐洲國家旅遊分級,哪個最美?金豬四國當仁不讓

盤點歐洲國家旅遊分級,哪個最美?金豬四國當仁不讓
從旅遊來講,各大洲歐洲是排第一的,亞洲緊隨其後,北美風景還行沒啥人文,中南美相對比較無聊,非洲澳洲更多看的是原始. 而在歐洲國家裡,如果說哪個最美,其實爭議挺大的,蘿蔔鹹菜各有所好,說哪個好貶低另一個 ...

歐洲小國家那麼多,為啥領土爭端卻很少?

歐洲小國家那麼多,為啥領土爭端卻很少?
自古以來,國家統一和領土完整就是每一個國家神聖不可侵犯的權力,為了維護國家利益,從古至今不知有多少好男兒效命沙場,為國征戰,甚至為國捐軀. 但由於種種歷史遺留原因,各國在邊界線的問題上也是公說公有理, ...

歐洲第一個對中國免籤的國家,風景美物價低,一張機票說走就走

歐洲第一個對中國免籤的國家,風景美物價低,一張機票說走就走
我們出國遊玩的時候最重要的就是簽證,世界上有一部分是對我國免籤的,那你知道在歐洲誰是第一個對中國免籤的嗎? 位於歐洲東南部的塞爾維亞共和國是歐洲國家第一個對中國免籤的國家,這個國家是巴爾幹半島的中部的 ...

歐洲有哪些國家不屬於歐盟?他們為什麼不加入?

歐洲有哪些國家不屬於歐盟?他們為什麼不加入?
1.瑞士,沒有加入原因:永久中立國,不加入任何組織. 2.英國,沒有加入原因:原本是歐盟成員國,後來發動脫歐公投玩脫了,當年卡相原本的意思是搞一次脫歐公投,料想不會過關,藉此機會打擊脫歐派政敵,誰曾想 ...

法國怒了!法外長直言莫里森像當初的特朗普,美法活動也被取消

法國怒了!法外長直言莫里森像當初的特朗普,美法活動也被取消
美.澳.法三國正在上演愛恨情仇.眾多網友看得不亦樂乎,除了法國網友在生悶氣以外. 現在法國不單單是被排擠的事情,更多是因為美國插了一腳,讓法國白白損失了一大筆軍火訂單.其實法國應該很明白美國的德性,可 ...

遭美英澳“暗算”?法國和歐盟怒了:背後捅刀,拜登就像特朗普
數百億美元大單泡湯.被矇在鼓裡直至官宣才知道,對於美英澳"私結"新安全同盟並幫助澳大利亞建造核潛艇的"背信棄義",法國和歐盟出離憤怒了. "背後捅刀& ...

570:61,歐洲議會壓倒性優勢透過一份反華決議,中歐關係面臨挑戰

570:61,歐洲議會壓倒性優勢透過一份反華決議,中歐關係面臨挑戰
根據環球網在9月17日的報道,歐洲議會在前一天的投票中,以570票贊成,61票反對和40票棄權的結果,壓倒性地通過了重新制定中歐戰略的決議案,該決議案被命名為新歐中戰略報告.歐洲議會要求歐盟在未來重新 ...

美法外交衝突爆發!被美英澳聯合捅刀,法國憤怒反擊,美急忙安撫

美法外交衝突爆發!被美英澳聯合捅刀,法國憤怒反擊,美急忙安撫
[南方+9月17日訊]據美國媒體報道,當地時間9月16日,由於與美.澳.英之間的新安全協議出現分歧,法國駐華盛頓大使館一怒之下取消了為紀念法國在切薩皮克灣海戰中取得勝利的晚會,並淡化了其他慶祝活動.正 ...

法國很生氣?其實在演戲!法國召回美澳大使背後的「利益雙簧戲」

法國很生氣?其實在演戲!法國召回美澳大使背後的「利益雙簧戲」
在外交話語體系中,召回大使是直接有力的外交警示,美國屢屢以此外交警示加之俄羅斯,歐盟也動不動以此威脅我國. 但誰都沒想到,身為西方陣營旗手的法國,會向"盟友"美國.澳大利亞,祭出召 ...

作為美國的盟友,為什麼法國和德國不購買F-35戰鬥機?

作為美國的盟友,為什麼法國和德國不購買F-35戰鬥機?
說到F35,很多人認為它是繼F22之後的又一款第五代隱形戰機,效能也非常出色.但是F35面臨著一個尷尬的問題:F35雖然銷量很大,但可以說幾乎所有盟國都有份額,但是法國和德國沒有購買! 老話說國防現代 ...

困擾歐洲多年的疑問:中國好像有花不完的錢

困擾歐洲多年的疑問:中國好像有花不完的錢
近十年來,中國以手中看似花不完的錢重新整理著世界對中國的看法.從中國出發,足跡遍佈五大洲.作為中國主要投資物件,歐洲國家已經越來越能感受到中國資本的存在. 根據長期跟蹤中國對外投資的美國智庫 Amer ...

歐洲局勢變了?9月18日,德防長聲援馬克龍,英國這次“賺大了”

歐洲局勢變了?9月18日,德防長聲援馬克龍,英國這次“賺大了”
山雨欲來風滿樓! 早在2019年,法國總統馬克龍便做出重要判斷:"美國正在背棄我們,北約正在經歷腦死亡." 到了今年的6月份,德國總理默克爾也鄭重指出:"隨著疫情大流行的 ...

南海國家喊話!澳圖謀裝備核潛艇後,印尼提醒:不要挑起軍備競賽

南海國家喊話!澳圖謀裝備核潛艇後,印尼提醒:不要挑起軍備競賽
澳大利亞這次與美英結成"新軍事夥伴關係",一切都進行得非常隱蔽,美英甚至連歐盟都沒打招呼.之所以是這三個國家"結盟",而且還明確表明針對亞太地區,主要是從&qu ...

一則關於歐洲女性卡車司機的故事,Desiree Bron和她的卡車大家庭

一則關於歐洲女性卡車司機的故事,Desiree Bron和她的卡車大家庭
在歐洲的卡車司機群體中,有一個有趣的現象:流入行業的年輕人越來越少,而女性卡車司機則越來越多.同時,年輕人主要是受童年的影響.家庭的薰陶而對卡車產生興趣並進入行業.為了吸引新卡車司機,政府.運輸公司和 ...

利司通將與EVBox合作在歐洲建設3,500個公共充電樁

利司通將與EVBox合作在歐洲建設3,500個公共充電樁
[高質量能源內容,點選右上角加'關注'] 據外媒報道,輪胎製造商和零售商普利司通已經與EVBox集團建立了長期合作關係,雙方將在歐洲部署多達3,500個交流和直流充電樁,由EVBox提供充電管理軟體. ...

局勢升級!法國召回駐美大使,專家:為了尊嚴,退出北約

局勢升級!法國召回駐美大使,專家:為了尊嚴,退出北約
世事複雜,總是一波未平一波又起. 在中美競爭博弈的大背景下,環太平洋地區早就開始"風起雲湧",隨著美國的世界戰略重心移向"印太",亞洲局勢進一步升級. 本週三, ...

北約歐洲迎來內訌,美國或對俄羅斯出手,加拿大對美不滿

北約歐洲迎來內訌,美國或對俄羅斯出手,加拿大對美不滿
澳大利亞撕毀與法國的核潛艇協議後,法國的反應相當激烈,以至於著實出人意料. 法國已經宣佈召回駐美國及澳大利亞大使,然而在法國看來,這對美國的抗議還不夠.美國擺明了不把法國放在眼裡.既然如此,法國似乎迎 ...

歐洲首位中國王妃,相貌平平迷倒王子,如今一家在中國定居

歐洲首位中國王妃,相貌平平迷倒王子,如今一家在中國定居
李然,是一個普通到不能再普通的名字,但是她的人格魅力和個人生活卻一點都不普通,從校園女神到比利時王妃,李然將人生活成了別人眼中的童話.婚後,她還不忘家鄉和祖國,把比利時王子"拐"到 ...