java 钉钉-第三方企业应用-免登
https://open.dingtalk.com/document/isvapp/sso-overview#title-lki-b8q-ar2
前端传输对象:
@Data
public class DingReq {
private String corpId;
private String authCode;
private String dingUserId;
private boolean isAdmin;
private List<String> userIdList;
private List<Long> deptIdList;
private String name;
private String projectName;
private String time;
private String templateId;
private String teacher;
}
钉钉-获取accessToken
/**
* ISV获取企业访问凭证
*
* @param corpId 授权企业的corpId
*/
@Override
public String getCorpToken(String corpId, String suiteTicket) {
if (StringUtils.isEmpty(corpId)) {
return null;
}
if (null != jedisClient.get(corpId)) {
return (String) jedisClient.get(corpId);
}
long timestamp = System.currentTimeMillis();
//正式应用应该由钉钉通过开发者的回调地址动态获取到
String signature = DingTalkSignatureUtil.computeSignature(Constant.SUITE_SECRET,
DingTalkSignatureUtil.getCanonicalStringForIsv(timestamp, suiteTicket));
Map<String, String> params = new LinkedHashMap<String, String>();
params.put("timestamp", String.valueOf(timestamp));
params.put("suiteTicket", suiteTicket);
params.put("accessKey", Constant.SUITE_KEY);
params.put("signature", signature);
String queryString = DingTalkSignatureUtil.paramToQueryString(params, "utf-8");
DingTalkClient client = new DefaultDingTalkClient(ApiUrlConstant.URL_GET_CORP_TOKEN + "?" + queryString);
OapiServiceGetCorpTokenRequest request = new OapiServiceGetCorpTokenRequest();
request.setAuthCorpid(corpId);
OapiServiceGetCorpTokenResponse response;
try {
response = client.execute(request);
if (null == response || StringUtils.isEmpty(response.getAccessToken())) {
log.error("获取token失败,response:{}", JSONUtil.toJsonStr(response));
return null;
}
log.info("获取企业acccessToken,serviceGetCorpTokenResponse:{}", JSONUtil.toJsonStr(response));
//设置过期时间,1小时50分钟
jedisClient.setStringExpire(corpId, response.getAccessToken(), 110 * 60);
} catch (ApiException e) {
log.error("获取token失败:", e, e);
return null;
}
if (response == null || !response.isSuccess()) {
log.error("获取token失败");
return null;
}
return response.getAccessToken();
}
钉钉-获取用户信息
/**
* 通过钉钉服务端API获取用户在当前企业的userId
*
* @param accessToken 企业访问凭证Token
* @param code 免登code
* @
*/
@Override
public OapiUserGetuserinfoResponse getOapiUserGetuserinfo(String accessToken, String code) {
DingTalkClient client = new DefaultDingTalkClient(ApiUrlConstant.URL_GET_USER_INFO);
OapiUserGetuserinfoRequest request = new OapiUserGetuserinfoRequest();
request.setCode(code);
request.setHttpMethod("GET");
OapiUserGetuserinfoResponse response;
try {
response = client.execute(request, accessToken);
} catch (ApiException e) {
e.printStackTrace();
return null;
}
log.info("通过钉钉服务端API获取用户在当前企业的userId:{}", JSONUtil.toJsonStr(response));
if (response == null || !response.isSuccess()) {
return null;
}
return response;
钉钉获取用户个人信息
/**
* 获取用户个人信息
*
* @param
* @return
* @throws Exception
*/
public GetUserTokenResponse getUserinfo(String code) throws Exception {
com.aliyun.dingtalkoauth2_1_0.Client client = createClient();
GetUserTokenResponse userToken = null;
GetUserTokenRequest getUserTokenRequest = new GetUserTokenRequest()
.setClientId(Constant.SUITE_KEY)
.setClientSecret(Constant.SUITE_SECRET)
.setCode(code)
.setGrantType("authorization_code");
//如果使用授权码换token,传authorization_code。
//如果使用刷新token换用户token,传refresh_token。
try {
userToken = client.getUserToken(getUserTokenRequest);
} catch (TeaException err) {
if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
// err 中含有 code 和 message 属性,可帮助开发定位问题
}
} catch (Exception _err) {
TeaException err = new TeaException(_err.getMessage(), _err);
if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
// err 中含有 code 和 message 属性,可帮助开发定位问题
}
}
return userToken;
}
钉钉-获取用户详细信息(获取用户手机号)
/**
* 获取用户详细信息
*
* @param accessToken
* @return
* @throws Exception
*/
@Override
public GetUserResponse getUseInfoDetail(String accessToken) throws Exception {
com.aliyun.dingtalkcontact_1_0.Client client = createClient_1_0();
com.aliyun.dingtalkcontact_1_0.models.GetUserHeaders getUserHeaders = new com.aliyun.dingtalkcontact_1_0.models.GetUserHeaders();
getUserHeaders.xAcsDingtalkAccessToken = accessToken;
GetUserResponse userWithOptions = null;
try {
userWithOptions = client.getUserWithOptions("me", getUserHeaders, new RuntimeOptions());
log.info("钉钉-获取用户详细信息,userWithOptions:{}", JSONUtil.toJsonStr(userWithOptions));
} catch (TeaException err) {
if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
// err 中含有 code 和 message 属性,可帮助开发定位问题
log.error("获取用户详细信息异常,err:{}", err);
}
} catch (Exception _err) {
TeaException err = new TeaException(_err.getMessage(), _err);
if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
// err 中含有 code 和 message 属性,可帮助开发定位问题
log.error("获取用户详细信息异常,err:{}", err);
}
}
return userWithOptions;
}
1、钉钉是否弹出授权框接口
●主要用来判断钉钉是否弹出授权框
●1、获取企业accessToken,通过前端传递的corpId,查询数据库中企业表对应的企业,找出suiteTicket,通过SuiteTicket和corpId得到企业accessToken
钉钉相关接口(https://oapi.dingtalk.com/service/get_corp_token)
●2、获取用户信息,通过企业accessToken和前端传递的authCode
钉钉相关接口(https://oapi.dingtalk.com/user/getuserinfo)
●3、查询得到钉钉当前用户的dingUserId,判断企业用户表是否存在该用户,用户为空,返回弹出授权标识
用户不为空,但是账号冻结,返回冻结标识
用户不为空但是username为空(说明没有手机号,获取手机号),返回弹出授权标识
有用户,返回用户信息。
public Result authLogin(@RequestBody DingReq ding) {
if (StringUtils.isEmpty(ding.getCorpId())) {
log.error("登录失败,缺少corpId");
return Result.succeed(false);
}
if (StringUtils.isEmpty(ding.getAuthCode())) {
log.error("缺少authCode");
return Result.succeed(false);
}
DingAuthVO dingAuthVO = new DingAuthVO();
dingAuthVO.setTag("no");
Tenant tenant = tenantMapper.findTenantInfo(ding.getCorpId());
SuiteTicket suiteTicket = suiteTicketMapper.findSuiteTicket();
if (null == suiteTicket) {
log.error("suiteTicket,为空");
return Result.succeed(false);
}
if (StringUtils.isEmpty(suiteTicket.getSuiteTicket())) {
log.error("登录失败,企业SuiteTicket为空");
return Result.succeed(false);
}
//获取accessToken,注意正是代码要有异常流处理
String accessToken = dingService.getCorpToken(ding.getCorpId(), suiteTicket.getSuiteTicket());
if (null == accessToken) {
log.error("登录失败,获取企业token失败");
return Result.succeed(false);
}
//获取用户信息
OapiUserGetuserinfoResponse oapiUserGetuserinfoResponse = dingService.getOapiUserGetuserinfo(accessToken, ding.getAuthCode());
if (null == oapiUserGetuserinfoResponse) {
log.error("登录失败,获取用户id失败");
return Result.succeed(false);
}
//3.查询得到当前用户的userId
// 获得到userId之后应用应该处理应用自身的登录会话管理(session),避免后续的业务交互(前端到应用服务端)每次都要重新获取用户身份,提升用户体验
String dingUserId = oapiUserGetuserinfoResponse.getUserid();
Boolean isAdmin = oapiUserGetuserinfoResponse.getIsSys();
dingAuthVO.setDingUserId(dingUserId);
dingAuthVO.setAdmin(isAdmin);
SysEntUser user = null;
if(null != tenant){
user = sysUserMapper.getUserInfo(tenant.getId(), null, dingUserId);
}
try {
if (null == user) {
//用户为空,返回弹出授权标识
log.info("用户为空,返回弹出授权标识");
dingAuthVO.setTag("userEmpty");
return Result.succeed(dingAuthVO);
} else {
if (!user.getEnabled()) {
dingAuthVO.setTag("frozen");
log.info("用户为被冻结");
return Result.succeed(dingAuthVO);
}
String username = user.getUsername();
if (StringUtils.isEmpty(username)) {
//账号为空,返回弹出授权标识
log.info("用户为空,返回弹出授权标识");
return Result.succeed(dingAuthVO);
}
String corpId = user.getCorpId();
if (StringUtils.isNotEmpty(corpId) && !corpId.equals(ding.getCorpId())) {
log.info("corpId和数据库不一样,进行更新");
sysUserMapper.updateDingSysUser(user.getId(), null, ding.getCorpId());
}
//返回用户信息
log.info("有用户,返回用户信息");
dingAuthVO.setTag("yes");
dingAuthVO.setUserId(user.getId());
dingAuthVO.setCropId(ding.getCorpId());
}
} catch (Exception e) {
e.printStackTrace();
}
return Result.succeed(dingAuthVO);
}
2、钉钉登录接口
●钉钉登录,查库,有数据生成token,没数据新增用户
●1、获取用户token,授权之后,前端传递authCode获取用户的accessToken
钉钉相关接口(/v1.0/oauth2/userAccessToken)
●2、获取用户详情,拿手机号
钉钉相关接口(/v1.0/contact/users/{unionId})
●3、根据前端传递的dingUserId,查询企业库用户表是否存在用户
如果无,新增管理员,判断是否为钉钉管理员,如果是就绑定管理员角色,
如果有,更新手机号和企业corpId
●4、钉钉-给第一个用户初始化直属部门
●5、返回用户信息
@Transactional(rollbackFor = Exception.class)
public Result dingLogin(@RequestBody DingReq ding) {
DingAuthVO dingAuthVO = new DingAuthVO();
try {
boolean isAdmin = ding.isAdmin();
if (StringUtils.isEmpty(ding.getCorpId())) {
log.error("登录失败,缺少corpId");
return Result.succeed(false);
}
if (StringUtils.isEmpty(ding.getAuthCode())) {
log.error("缺少authCode");
return Result.succeed(false);
}
if (StringUtils.isEmpty(ding.getDingUserId())) {
log.error("缺少dingUserId");
return Result.succeed(false);
}
Tenant tenant = tenantMapper.findTenantInfo(ding.getCorpId());
if (null == tenant) {
log.error("登录失败,企业还未初始化");
return Result.succeed(false);
}
//获取用户token
GetUserTokenResponse userinfo = dingService.getUserinfo(ding.getAuthCode());
if (null == userinfo) {
log.error("获取用户token失败");
return Result.succeed(false);
}
String token = userinfo.getBody().getAccessToken();
//获取用户详情,拿手机号
GetUserResponse useInfo = dingService.getUseInfoDetail(token);
if (null == useInfo) {
log.error("获取用户详情失败");
return Result.succeed(false);
}
String mobile = useInfo.getBody().getMobile();
if (StringUtils.isEmpty(mobile)) {
log.error("获取用户电话失败");
return Result.succeed(false);
}
String avatarUrl = useInfo.getBody().getAvatarUrl();
String email = useInfo.getBody().getEmail();
String nick = useInfo.getBody().getNick();
SysEntUser sysUser = sysUserMapper.getUserInfo(tenant.getId(), null, ding.getDingUserId());
if (null == sysUser) {
//新增用户
log.info("钉钉-新增管理员");
sysUser = new SysEntUser();
。。。。
if (isAdmin) {
//是管理员才会给管理员设置角色
log.info("钉钉-给管理员设置角色");
sysUserMapper.addSysUser(sysUser);
List<SysRole> sysRoles = sysRoleMapper.selectSysRole(tenant.getId());
if (CollectionUtils.isNotEmpty(sysRoles)) {
//找到管理员角色
SysRole admin = sysRoles.stream().filter(v -> v.getCode().equals("ADMIN")).collect(Collectors.toList()).get(0);
if (null != admin) {
sysUserRoleMapper.addUserRole(sysUser.getId(), admin.getId(), tenant.getId());
}
}
}
} else {
log.info("更新手机号和企业corpId");
sysUserMapper.updateDingSysUser(sysUser.getId(), mobile, ding.getCorpId());
}
DepartmentVO departmentVO = departmentMapper.findInfo(tenant.getId(), 1);
if (null != departmentVO) {
log.info("钉钉-给第一个用户初始化直属部门");
DepartUser departUser = new DepartUser();
。。。
departUserMapper.saveDepartUser(departUser);
}
log.info("用户信息:{}", JSONUtil.toJsonStr(sysUser));
dingAuthVO.setUserId(sysUser.getId());
dingAuthVO.setCropId(ding.getCorpId());
} catch (Exception e) {
e.printStackTrace();
}
return Result.succeed(dingAuthVO);
}