微信開放平臺(tái):微信掃碼登錄功能
正式文件:
1.批準(zhǔn)流程說明
微信OAu認(rèn)證登錄允許微信用戶使用微信id安全登錄第三方應(yīng)用程序或網(wǎng)站,在微信用戶授權(quán)訪問微信OAu的第三方應(yīng)用程序登錄后,第三方可以獲取用戶的接口調(diào)用憑證(access_token),通過ACESS _ TOKEN可以進(jìn)行微信開放平臺(tái)認(rèn)證關(guān)系接口調(diào)用,從而獲得微信用戶的基本開放信息
微信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ù);
② 通過code參數(shù)加上AppID和AppSecret等,通過API換取access_token;
③ 通過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)頁授權(quán)作用域(scope=snsapi_login),則可以通過在PC端打開以下鏈接:;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
例如:登錄一號(hào)店網(wǎng)站應(yīng)用 打開后,一號(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
第二步:通過code獲取access_token
通過code獲取access_token
;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ǔ)在客戶端,極有可能被惡意竊取(如反編譯獲取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)用請(qǐng)求。
第三步:通過access_token調(diào)用接口
獲取access_token后,進(jìn)行接口調(diào)用,有以下前提:
- access_token有效且未超時(shí);
- 微信用戶已授權(quán)給第三方應(yīng)用帳號(hào)相應(yīng)接口作用域(scope)。
對(duì)于接口作用域(scope),能調(diào)用的接口有以下:
2. 授權(quán)流程代碼
因?yàn)槲⑿砰_放平臺(tái)的AppiD和APPSecret和微信公眾平臺(tái)的AppiD和AppSecret都是不同的,因此需要配置一下:
# 開放平臺(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;
//商戶證書路徑
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();
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)用戶訪問這個(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 {
//通過code獲取access_token
wxMpOAuth2AccessToken = wxO(code);
} catch (WxErrorException e) {
log.error("【微信網(wǎng)頁授權(quán)】{}", e);
throw new SellException(), e.getError().getErrorMsg());
}
//從token中獲取openid
String openId = wxM();
//這個(gè)地址可有可無,反正只是為了拿到openid,但是如果沒有會(huì)報(bào)404錯(cuò)誤,為了好看隨便返回一個(gè)百度的地址
String returnUrl = ";;
log.info("openid={}", openId);
return "redirect:" + returnUrl + "?openid="+openId;
}
}
請(qǐng)求路徑:在瀏覽器打開
;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ù)庫里的數(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的過期時(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ù)庫
② 將授權(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 {
//通過code獲取access_token
wxMpOAuth2AccessToken = wxO(code);
} catch (WxErrorException e) {
log.error("【微信網(wǎng)頁授權(quán)】{}", e);
throw new SellException(), e.getError().getErrorMsg());
}
//從token中獲取openid
String openId = wxM();
//授權(quán)成功后跳轉(zhuǎn)到賣家系統(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)用戶有沒有登錄
@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中沒有token說明已經(jīng)登出或者根本沒有登錄
if (cookie == null) {
log.warn("【登錄校驗(yàn)】Cookie中查不到token");
//校驗(yàn)不通過,拋出異常
throw new SellerAuthorizeException();
}
//去redis里查詢
String tokenValue = redi().ge, cookie.getValue()));
//如果redis中沒有對(duì)應(yīng)的openid,同樣表示登出或者根本沒有登錄
if (tokenValue)) {
log.warn("【登錄校驗(yàn)】Redis中查不到token");
throw new SellerAuthorizeException();
}
}
}
5. 攔截登錄校驗(yàn)不通過拋出的異常
攔截及登錄校驗(yàn)不通過的異常,讓其跳轉(zhuǎn)到登錄頁面,掃碼登錄
@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() {
}
}
來源:
1.《微信怎么用二維碼登陸不了怎么辦?終于找到答案了微信掃碼登錄很難嗎?5步幫你搞定》援引自互聯(lián)網(wǎng),旨在傳遞更多網(wǎng)絡(luò)信息知識(shí),僅代表作者本人觀點(diǎn),與本網(wǎng)站無關(guān),侵刪請(qǐng)聯(lián)系頁腳下方聯(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)容來源地址,http://f99ss.com/gl/2975818.html