uni-app微信公衆号web JS-SDK開發之(zhī)二授權登錄
發表時(shí)間:2020-9-30
發布人(rén):融晨科技
浏覽次數:99
前言
不(bù)了(le/liǎo)解如何接入JS-SDK的(de)可以(yǐ)先看看上(shàng)篇文章uni-app微信公衆号web JS-SDK開發之(zhī)一接入
目标
- 通過微信授權登錄到(dào)系統
微信登錄原理
注意上(shàng)面的(de)域名信息
實現微信登錄
先看一下微信文檔了(le/liǎo)解一下:網頁授權
回調域名配置(必須配置,是(shì)頁面不(bù)是(shì)接口)
後端實現code換OpenId
使用weixin-java-mp
maven依賴
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>3.9.0</version>
</dependency>
我沒用starter版,自己定義更靈活
初始化WxMpService
@Component
public class WxMpServiceDaemon {
private WxMpService wxMpService;
private String configHash;
/**
* get後不(bù)要(yào / yāo)緩存,因爲(wéi / wèi)會被因配置的(de)改變而(ér)實時(shí)刷新
*/
public WxMpService getWxMpService() {
if (StringUtils.isBlank(ProjectWxMpConfigBean.INSTANCE.getAppId())) {
throw new RuntimeException("未配置公衆号AppId等字段");
}
if (StringUtils.isBlank(ProjectWxMpConfigBean.INSTANCE.getSecret())) {
throw new RuntimeException("未配置公衆号AppSecret等字段");
}
String hash = SecureUtil.md5(ProjectWxMpConfigBean.INSTANCE.getAppId() + ProjectWxMpConfigBean.INSTANCE.getSecret() + ProjectWxMpConfigBean.INSTANCE.getToken() + ProjectWxMpConfigBean.INSTANCE.getAesKey());
if (hash.equals(configHash) && null != wxMpService) {
//配置未變,使用緩存
return wxMpService;
}
WxMpServiceImpl wxMpService = new WxMpServiceImpl();
WxMpDefaultConfigImpl conf = new WxMpDefaultConfigImpl();
conf.setAppId(ProjectWxMpConfigBean.INSTANCE.getAppId());
conf.setSecret(ProjectWxMpConfigBean.INSTANCE.getSecret());
conf.setToken(ProjectWxMpConfigBean.INSTANCE.getToken());
conf.setAesKey(ProjectWxMpConfigBean.INSTANCE.getAesKey());
wxMpService.setWxMpConfigStorage(conf);
configHash = hash;
this.wxMpService = wxMpService;
return wxMpService;
}
}
自定義了(le/liǎo)WxMpServiceDaemon
來(lái)獲取WxMpService,這(zhè)種方式可以(yǐ)根據配置信息的(de)改變而(ér)實時(shí)刷新WxMpService實現熱更換
code換OpenId
@Component
@Slf4j
public class WxmpAuthServiceImpl implements UserDetailsService {
@Resource
private AppUserWriteBiz appUserWriteBiz;
@Resource
private AppUserReadBiz appUserReadBiz;
private Cache<String, String> codeCache = CacheBuilder.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES).build();
@Resource
private WxMpServiceDaemon wxMpServiceDaemon;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
WxMpOAuth2AccessToken session = null;
String openId = "";
synchronized (s.intern()) {
openId = codeCache.getIfPresent(s);
if (StringUtils.isBlank(openId)) {
try {
session = wxMpServiceDaemon.getWxMpService().getOAuth2Service().getAccessToken(s);
} catch (WxErrorException e) {
log.error("login by weixin mp error", e);
throw new BizException("微信登錄錯誤");
}
openId = session.getOpenId();
codeCache.put(s, openId);
}
}
String finalOpenId = openId;
AppUser appUser = Optional.ofNullable(appUserReadBiz.getByMpOpenId(openId)).orElseGet(() -> appUserWriteBiz.createMpUser(finalOpenId));
if (null == appUser) {
return null;
}
return new User(openId, appUser.getPassword(), getAuthorities());
}
private Collection<GrantedAuthority> getAuthorities() {
List<GrantedAuthority> authList = new ArrayList<>();
authList.add(new SimpleGrantedAuthority("ROLE_USER"));
return authList;
}
}
這(zhè)裏是(shì)基于(yú)Spring Security OAuth2實現的(de),可以(yǐ)根據關鍵代碼提煉
說(shuō)明一下這(zhè)裏的(de)code即變量s,由于(yú)可能存在(zài)code重複訪問、并發訪問的(de)問題,所以(yǐ)我們加了(le/liǎo)鎖和(hé / huò)使用了(le/liǎo)緩存來(lái)存儲code和(hé / huò)openId關系,但這(zhè)裏注意一下,這(zhè)裏有安全隐患比如code洩露重複獲取登錄token,爲(wéi / wèi)了(le/liǎo)避免這(zhè)樣的(de)問題,我們可以(yǐ)将接口api進行url簽名保證每個(gè)請求的(de)唯一性以(yǐ)及不(bù)可重複性。如果不(bù)想這(zhè)麽麻煩就(jiù)把codeCache給去掉。