uni-app微信公众号web JS-SDK开发之二授权登录
发表时间:2020-9-30
发布人:葵宇科技
浏览次数:83
前言
不了解如何接入JS-SDK的可以先看看上篇文章uni-app微信公众号web JS-SDK开发之一接入
目标
- 通过微信授权登录到系统
微信登录原理
注意上面的域名信息
实现微信登录
先看一下微信文档了解一下:网页授权
回调域名配置(必须配置,是页面不是接口)
后端实现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后不要缓存,因为会被因配置的改变而实时刷新
*/
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;
}
}
自定义了WxMpServiceDaemon
来获取WxMpService,这种方式可以根据配置信息的改变而实时刷新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;
}
}
这里是基于Spring Security OAuth2实现的,可以根据关键代码提炼
说明一下这里的code即变量s,由于可能存在code重复访问、并发访问的问题,所以我们加了锁和使用了缓存来存储code和openId关系,但这里注意一下,这里有安全隐患比如code泄露重复获取登录token,为了避免这样的问题,我们可以将接口api进行url签名保证每个请求的唯一性以及不可重复性。如果不想这么麻烦就把codeCache给去掉。