文章讲述如何在开发钉钉小程序的时候,实现免登陆功能,本系统基于RuoYi SpringBoot3版本测试,有些类找不到可以去RuoYi官网查看。
钉钉小程序开发时,需要实现免登陆功能,即用户在钉钉小程序无需账号密码登录,后续进入小程序,也不需要再次登录。
调用 dd.getAuthCode,获取应用免登授权码
文档地址:https://open.dingtalk.com/document/orgapp/jsapi-get-auth-code
const { authCode } = await dd.getAuthCode();
使用httpRequest发送authCode给服务器,在钉钉小程序发送请求需要JSON.stringify()一下
文档地址:https://open.dingtalk.com/document/orgapp/jsapi-http-request
const res = await dd.httpRequest({
url: 'http://note.studiogm.cn/dingtalk/login',
data: JSON.stringify({
code: authCode
}),
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
timeout: 30000,
dataType
})
使用SpringBoot做演示
实体类文件SysAuthUser.java
package com.gm.system.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@TableName("sys_auth_user")
public class SysAuthUser {
/**
* 授权ID
*/
@TableId(value = "auth_id", type = IdType.AUTO)
private Long authId;
/**
* 第三方平台用户唯一ID
*/
private String uuid;
/**
* 系统用户ID
*/
private Long userId;
/**
* 登录账号
*/
private String userName;
/**
* 用户昵称
*/
private String nickName;
/**
* 头像地址
*/
private String avatar;
/**
* 用户邮箱
*/
private String email;
/**
* 用户来源
*/
private String source;
/**
* 创建时间
*/
private Date createTime;
}
AuthUserLoginDTO.java
package com.gm.dingtalk.domain.dto;
import lombok.Data;
@Data
public class AuthUserLoginDTO {
private String code;
}
DingTalkLoginVO.java
package com.gm.dingtalk.domain.vo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class DingTalkLoginVO {
/**
* 设备ID
*/
private String deviceId;
/**
* 用户名称
*/
private String name;
/**
* 是否是管理员
*/
private Boolean sys;
/**
* 系统级别
*/
private Integer sysLevel;
/**
* 用户在钉钉的唯一标识
*/
private String unionid;
/**
* 用户ID
*/
private String userid;
}
Controller文件 DingTalkLoginController.java
package com.gm.web.controller.dingtalk;
import com.gm.common.constant.Constants;
import com.gm.common.constant.HttpStatus;
import com.gm.common.core.controller.BaseController;
import com.gm.common.core.domain.AjaxResult;
import com.gm.common.exception.ServiceException;
import com.gm.dingtalk.domain.dto.AuthUserLoginDTO;
import com.gm.dingtalk.domain.vo.DingTalkLoginVO;
import com.gm.dingtalk.service.AuthUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/dingtalk")
public class DingTalkLoginController extends BaseController {
@Autowired
private AuthUserService authUserService;
/**
* 钉钉登录
* @param authUserLoginDTO
* @return
* @throws Exception
*/
@PostMapping("/login")
public AjaxResult login(@RequestBody AuthUserLoginDTO authUserLoginDTO) throws Exception{
if ( authUserLoginDTO.getCode() == null) {
throw new ServiceException("code不能为空", HttpStatus.BAD_REQUEST);
}
AjaxResult ajax = AjaxResult.success();
// 生成令牌
String token = authUserService.loginByDingCode(authUserLoginDTO.getCode());
ajax.put(Constants.TOKEN, token);
return ajax;
}
}
Service文件 AuthUserService.java
package com.gm.dingtalk.service;
import com.aliyun.dingtalkoauth2_1_0.Client;
import com.aliyun.dingtalkoauth2_1_0.models.GetTokenRequest;
import com.aliyun.dingtalkoauth2_1_0.models.GetTokenResponse;
import com.aliyun.tea.TeaException;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.Common;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiV2UserGetuserinfoRequest;
import com.dingtalk.api.response.OapiV2UserGetuserinfoResponse;
import com.gm.common.constant.HttpStatus;
import com.gm.common.core.domain.entity.SysUser;
import com.gm.common.core.domain.model.LoginUser;
import com.gm.common.exception.ServiceException;
import com.gm.common.utils.DateUtils;
import com.gm.common.utils.SecurityUtils;
import com.gm.common.utils.ip.IpUtils;
import com.gm.dingtalk.config.DingTalkConfig;
import com.gm.framework.web.service.SysPermissionService;
import com.gm.system.domain.SysAuthUser;
import com.gm.dingtalk.domain.vo.DingTalkLoginVO;
import com.gm.system.mapper.SysAuthUserMapper;
import com.gm.system.service.ISysConfigService;
import com.gm.system.service.ISysUserService;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.gm.framework.web.service.TokenService;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
@Service
public class AuthUserService extends ServiceImpl<SysAuthUserMapper, SysAuthUser> implements IService<SysAuthUser> {
@Autowired
private SysAuthUserMapper sysAuthUserMapper;
@Autowired
private ISysUserService userService;
@Autowired
private TokenService tokenService;
@Autowired
private SysPermissionService permissionService;
@Autowired
private DingTalkConfig dingTalkConfig;
@Autowired
private ISysConfigService sysConfigService;
public static Client createClient() throws Exception {
Config config = new Config();
config.protocol = "https";
config.regionId = "central";
return new Client(config);
}
/**
* 钉钉登录
*
* @param code
* @return nil
* @throws Exception
*/
@Transactional
public String loginByDingCode(String code) throws Exception {
try {
// 通过code获取用户信息
DingTalkLoginVO dingTalkLoginVO = getDingTalkLoginVOByCode(code);
// 判断当前用户是否有授权信息
SysAuthUser sysAuthUser = sysAuthUserMapper.selectByUuid(dingTalkLoginVO.getUnionid());
if (sysAuthUser != null) {
// 该用户已有授权信息
Long userId = sysAuthUser.getUserId();
SysUser user = userService.selectUserById(userId);
return genToken(user);
} else {
// 第一次授权
// 注册用户
SysUser sysUser = createSysUser(dingTalkLoginVO);
// 新增授权用户关联信息
SysAuthUser newAuthUser = SysAuthUser.builder()
.userId(sysUser.getUserId())
.uuid(dingTalkLoginVO.getUnionid())
.userName(dingTalkLoginVO.getName())
.nickName(sysUser.getUserName())
.source("钉钉")
.createTime(new Date())
.build();
int insert = sysAuthUserMapper.insert(newAuthUser);
// 判断失败
if (insert <= 0) {
throw new ServiceException("用户授权失败", HttpStatus.ERROR);
}
return genToken(sysUser);
}
} catch (TeaException err) {
// err.code 和 err.message 获取异常信息
if (!Common.empty(err.code) && !Common.empty(err.message)) {
// err 中含有 code 和 message 属性,可帮助开发定位问题
throw new ServiceException(err.message, HttpStatus.ERROR);
}
} catch (Exception _err) {
// 获取异常信息
TeaException err = new TeaException(_err.getMessage(), _err);
if (!Common.empty(err.code) && !Common.empty(err.message)) {
// err 中含有 code 和 message 属性,可帮助开发定位问题
throw new ServiceException(err.message, HttpStatus.ERROR);
}
}
return null;
}
/**
* 获取钉钉用户信息
* @param dingTalkLoginVO
* @return
*/
@NotNull
private SysUser createSysUser(DingTalkLoginVO dingTalkLoginVO) {
SysUser sysUser = new SysUser();
sysUser.setNickName(dingTalkLoginVO.getName());
sysUser.setUserName("gm-" + dingTalkLoginVO.getUserid());
sysUser.setStatus("0");
sysUser.setLoginIp(IpUtils.getIpAddr());
sysUser.setLoginDate(DateUtils.getNowDate());
sysUser.setCreateBy("owner");
sysUser.setPassword(SecurityUtils.encryptPassword(sysConfigService.selectConfigByKey("sys.user.initPassword")));
sysUser.setCreateTime(DateUtils.getNowDate());
sysUser.setDelFlag("0");
sysUser.setDeptId(100L); // 根部门
boolean b = userService.registerUser(sysUser);
if (!b) {
throw new ServiceException("注册用户失败");
}
return sysUser;
}
/**
* 记录登录信息
*
* @param userId 用户ID
*/
public void recordLoginInfo(Long userId) {
SysUser sysUser = new SysUser();
sysUser.setUserId(userId);
sysUser.setLoginIp(IpUtils.getIpAddr());
sysUser.setLoginDate(DateUtils.getNowDate());
userService.updateUserProfile(sysUser);
}
/**
* 生成token
* @param user
* @return
*/
public String genToken(SysUser user) {
LoginUser loginUser = new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));;
recordLoginInfo(user.getUserId());
return tokenService.createToken(loginUser);
}
/**
* 获取钉钉用户信息
* @param code
* @return
* @throws Exception
*/
public DingTalkLoginVO getDingTalkLoginVOByCode(String code) throws Exception {
// 创建客户端
Client client = createClient();
GetTokenRequest getTokenRequest = new GetTokenRequest()
.setClientId(dingTalkConfig.getClientId())
.setClientSecret(dingTalkConfig.getClientSecret())
.setGrantType("client_credentials");
// 获取AccessToken
GetTokenResponse token = client.getToken(dingTalkConfig.getCorpId(), getTokenRequest);
String access_token = token.body.accessToken;
// 获取user_id
DingTalkClient client1 = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/getuserinfo");
OapiV2UserGetuserinfoRequest req = new OapiV2UserGetuserinfoRequest();
req.setCode(code);
OapiV2UserGetuserinfoResponse rsp = client1.execute(req, access_token);
// 转成DingTalkLoginVO
DingTalkLoginVO dingTalkLoginVO = new DingTalkLoginVO();
BeanUtils.copyProperties(rsp.getResult(), dingTalkLoginVO);
return dingTalkLoginVO;
}
}
Mapper文件 AuthUserMapper.java
package com.gm.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.gm.system.domain.SysAuthUser;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface SysAuthUserMapper extends BaseMapper<SysAuthUser> {
@Select( "select * from sys_auth_user where uuid = #{uuid}")
SysAuthUser selectByUuid(String uuid);
}
配置类文件 DingTalkConfig.java
package com.gm.dingtalk.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "dingtalk")
public class DingTalkConfig {
/**
* 企业ID corpId
*/
private String corpId;
/**
* 应用ID clientId
*/
private String clientId;
/**
* 应用密钥 clientSecret
*/
private String clientSecret;
}
配置文件 application.yml
dingtalk:
corpId: xxx
clientId: xxx
clientSecret: xxx
原文地址(本人站点):https://codels.gmcoder.cn/blog/ding-talk-login
如果对您有帮助的话请点点关注,感谢支持