准备资源
- 登录微信开放平台,网址 https://open.weixin.qq.com/cgi-bin/index?t=home/index&lang=zh_CN&token=d0e8460e976b6641b42246a7dd194147de99212b
- 进入管理中心
- 选择网站应用
- 创建一个应用,需要根据域名,公司需要提供一个盖章文件,以及公司资质文件,进行申请,申请成功后即可获得 appid 和 密钥 口令
后端部分
后端这里我们借助"justauth"框架,这里我们只需要提供一个登录接口即可
- 流程图
- 登录接口代码如下:
public Result<String> login(AuthCallback callback, AuthRequest authRequest) {
// 使用justauth框架进行登录
AuthResponse authResponse = authRequest.login(callback);
// 校验登录是否成功,如果失败直接抛出异常
dingtalkRequestUtil.checkRequestIsSuccess(authResponse, "微信登录异常");
// 获取登录成功的用户信息
AuthUser authUser = (AuthUser) authResponse.getData();
// 微信平台的用户唯一id
String userOpenId = authUser.getToken().getOpenId();
// 查询用户是否存在
SysUserDO sysUserDO = sysUserRepository.findByOpenId(userOpenId);
// 用户存在签发token
if (sysUserDO != null) {
// 执行token签发
Subject subject = subjectService.getSubject(sysUserDO, sysUserDO.getUsername());
return Result.success(tokenService.generateToken(subject));
} else {
// 用户不存在返回openid 需要进行绑定用户操作
// 绑定用户
return new Result(ResultCode.UNREGISTERED.getCode(), userOpenId, ResultCode.UNREGISTERED.getMsg(), 0);
}
}
- 工具类 (这个工具类为公用,所以这里不在赘述,里面含有顶顶登录的代码,用不到不用关注,删除即可)
/**
* 三方登录请求工具类
*/
@Component
@Slf4j
public class TripartiteLoginRequestUtil {
// 类型为 钉钉
public static final String TYPE = "DINGTALK";
// 钉钉token
public static final String TOKEN = "TOKEN";
// 成功状态
public static final Integer SUCCESS_STATUS_1 = 2000;
public static final Integer SUCCESS_STATUS_2 = 0;
private final RestTemplate restTemplate;
private final MongCacheUtil mongCacheUtil;
@Value("${justauth.type.DINGTALK.client-id}")
private String appkey;
@Value("${justauth.type.DINGTALK.client-secret}")
private String appsecret;
@Value("${justauth.type.DINGTALK.gettoken-url}")
private String gettokenUrl;
@Value("${justauth.type.DINGTALK.get-user-info-url}")
private String getUserInfoUrl;
@Value("${justauth.type.DINGTALK.get-userid-by-unionid}")
private String getUseridByUnionid;
@Value("${justauth.type.DINGTALK.get-userinfo-by-userid}")
private String getUserinfoByUserid;
@Autowired
public TripartiteLoginRequestUtil(RestTemplate restTemplate, MongCacheUtil mongCacheUtil) {
this.restTemplate = restTemplate;
this.mongCacheUtil = mongCacheUtil;
}
/**
* token 的过期时间,默认为两个小时
*
* @return
*/
public String getToken() {
// 从缓存中查询当前的token
String cacheKey = TYPE + "_" + TOKEN;
Result<String> cache = mongCacheUtil.get(cacheKey);
if (Objects.equals(cache.getCode(), ResultCode.SUCCESS.getCode())) {
return cache.getData();
} else {
String url = gettokenUrl + "?appkey=" + appkey + "&appsecret=" + appsecret;
Map forObject = restTemplate.getForObject(url, Map.class);
checkRequestIsSuccess(forObject, "获取钉钉token异常", forObject);
String accessToken = forObject.get("access_token").toString();
// 设置缓存
mongCacheUtil.put(cacheKey, accessToken, Integer.parseInt(forObject.get("expires_in").toString()), 900);
return accessToken;
}
}
/**
* 检查请求是否成功
*
* @param resp
*/
public void checkRequestIsSuccess(Object resp, String errMessage, Object... errObjects) {
boolean error = false;
if (resp instanceof AuthResponse) {
AuthResponse authResponse = (AuthResponse) resp;
if (!Objects.equals(authResponse.getCode(), SUCCESS_STATUS_1)) {
error = true;
}
} else if (resp instanceof Map) {
Map<String, String> resMap = (Map<String, String>) resp;
if (!resMap.containsKey("errcode") || !Objects.equals(String.valueOf(resMap.get("errcode")), SUCCESS_STATUS_2.toString())) {
error = true;
errMessage = resMap.get("errmsg");
}
}
if (error) {
log.error(JSON.toJSONString(errObjects));
throw new DingtalkRequestException(errMessage);
}
}
public String getUserId(String token, String unionId) {
String url = getUseridByUnionid + "?access_token=" + token + "&unionid=" + unionId;
Map respMap = restTemplate.getForObject(url, Map.class);
System.out.println(respMap);
checkRequestIsSuccess(respMap, "获取用户id异常", respMap);
// 校验是否成功
return respMap.get("userid").toString();
}
public DingtalkUserDO getUserInfo(String token, String userId) {
String url = getUserinfoByUserid + "?access_token=" + token + "&userid=" + userId;
Map respMap = restTemplate.getForObject(url, Map.class);
checkRequestIsSuccess(respMap, "获取用户信息异常");
// 转换为自己的实体 DingtalkUserDO
return com.alibaba.fastjson.JSON.parseObject(JSON.toJSONString(respMap), DingtalkUserDO.class);
}
/**
* 钉钉异常内部类
*/
class DingtalkRequestException extends RuntimeException {
public DingtalkRequestException(String message) {
super(message);
}
}
}
前端部分
前端我们使用的vue
- public/index.html中引入js文件,内容如下,名称自己定义
!function(a,b,c){function d(a){var c="default";a.self_redirect===!0?c="true":a.self_redirect===!1&&(c="false");var d=b.createElement("iframe"),e="https://open.weixin.qq.com/connect/qrconnect?appid="+a.appid+"&scope="+a.scope+"&redirect_uri="+a.redirect_uri+"&state="+a.state+"&login_type=jssdk&self_redirect="+c+'&styletype='+(a.styletype || '')+'&sizetype='+(a.sizetype || '')+'&bgcolor='+(a.bgcolor || '')+'&rst='+(a.rst || '');e+=a.style?"&style="+a.style:"",e+=a.href?"&href="+a.href:"",d.src=e,d.frameBorder="0",d.allowTransparency="true",d.scrolling="no",d.width="300px",d.height="400px";var f=b.getElementById(a.id);f.innerHTML="",f.appendChild(d)}a.WxLogin=d}(window,document);
- 获取微信登录二维码代码如下
var obj = new WxLogin({
id: 'login_container',
appid: 你的appid,
scope: 'snsapi_login',
state: nanoid(),
style: 'white',
redirect_uri: encodeURIComponent('你的重定向地址')
})