序
企业内部系统已经做过了钉钉扫码登录,现在需要添加钉钉一键登录第三方网站功能,这里主要记录一键登录整个实现步骤。
钉钉开发者后台
想要实现钉钉一键登录,首先需要在钉钉开放平台管理平台配置H5微应用
H5微应用
实现钉钉一键登录第三方网站,官方文档地址:实现登录第三方网站根据官方文档的操作步骤来看的话需要先到钉钉开发者后台添加H5微应用,钉钉开发者后台地址:钉钉开发者后台进入钉钉开发者后台后,
选择【企业内部开发】进入
点击右上角【创建应用】
输入【应用名称】,【应用描述】,上传系统图标或者不上传都可以,点击【确认创建】
创建完成之后你就可以看到你创建的H5微应用的应用凭证,点击左侧菜单【权限管理】
这里需要申请【个人手机号信息】、【通讯录个人信息读权限】两个权限,权限申请完成之后点击菜单【登录与分享】
在输入框中输入回调的域名及对应的方法,点击【添加】完成回调URL的配置,这里因为是三套环境(开发、测试、线上),所以配置三套回调URL,三套环境用同一套应用凭证,当然你也可以选择创建三个H5微应用来支持三套环境。
应用代码开发
首先需要在登录页构造钉钉一键登录跳转链接,构造链接参考官方文档
登录页面login.html
登录页面构造好钉钉一键登录链接后的页面效果
页面代码,在原有的登录页面中添加如下代码
<divstyle="padding-left: 83px;"><buttontype="button"class="btn-dingding"onclick="toDingDing();">钉钉一键授权登录</button></div>
同时在页面增加跳转方法
//钉钉一键授权登录functiontoDingDing() { varprojectUrl=$("#projectUrl").val(); varh5AppKey=$("#h5AppKey").val(); varredirect_uri=projectUrl+"dingdingOneClickLogin"; redirect_uri=encodeURIComponent(redirect_uri); self.location="https://login.dingtalk.com/oauth2/auth?redirect_uri="+redirect_uri+"&response_type=code&client_id="+h5AppKey+"&scope=openid&state=&prompt=consent"; }
其中:projectUrl 就是获取的请求域名地址
h5AppKey 就是配置的H5微应用的AppKey
至此,页面的内容添加完毕,下面开始来增加后台Java方法
登录实现LoginController.java
登录实现controller需要增加如下方法
/*** 登录系统* @param use* @return*/privateStringdoLoginSystem(SysUseruse) { //已绑定账号则直接登录操作MyUsernamePasswordTokentoken=newMyUsernamePasswordToken(use.getUnionId(), use.getPassword(),false,true); // 登陆主流程Subjectsubject=SecurityUtils.getSubject(); subject.login(token); returnredirect("/index"); } publicstaticcom.aliyun.dingtalkoauth2_1_0.ClientauthClient() throwsException { Configconfig=newConfig(); config.protocol="https"; config.regionId="central"; returnnewcom.aliyun.dingtalkoauth2_1_0.Client(config); } /*** 获取用户token* @param authCode* @return* @throws Exception*///接口地址:注意/auth与钉钉登录与分享的回调域名地址一致value="/dingdingOneClickLogin", method=RequestMethod.GET) (publicStringgetAccessToken( (value="authCode")StringauthCode) throwsException { com.aliyun.dingtalkoauth2_1_0.Clientclient=authClient(); GetUserTokenRequestgetUserTokenRequest=newGetUserTokenRequest() //应用基础信息-应用信息的AppKey,请务必替换为开发的应用AppKey .setClientId(dingDingProperties.getH5AppKey()) //应用基础信息-应用信息的AppSecret,,请务必替换为开发的应用AppSecret .setClientSecret(dingDingProperties.getH5AppSecret()) .setCode(authCode) .setGrantType("authorization_code"); GetUserTokenResponsegetUserTokenResponse=client.getUserToken(getUserTokenRequest); //获取用户个人tokenStringaccessToken=getUserTokenResponse.getBody().getAccessToken(); GetUserResponseBodyuserinfo=getUserinfo(accessToken); //根据unionId 获取用户信息StringunionId=userinfo.getUnionId(); SysUseruse=sysUserService.selectUserByUnionId(unionId); Stringmsg=""; if (use!=null) { returndoLoginSystem(use); }else { //未绑定 则自动添加账号 根据unionid获取useridOapiUserGetbyunionidResponse.UserGetByUnionIdResponseuserIdByUnionIdV2=dingDingService.getUserIdByUnionIdV2(unionId); if (userIdByUnionIdV2!=null&&StringUtils.isNotEmpty(userIdByUnionIdV2.getUserid())) { //根据userid获取用户详细信息OapiV2UserGetResponse.UserGetResponseuser=dingDingService.getUserDetailByUserid(userIdByUnionIdV2.getUserid(), null); if (user!=null) { returnsaveSysUserAuto(user); }else { msg="one"; } }else { msg="one"; } } returnredirect("/login?msg="+msg); } publicstaticcom.aliyun.dingtalkcontact_1_0.ClientcontactClient() throwsException { Configconfig=newConfig(); config.protocol="https"; config.regionId="central"; returnnewcom.aliyun.dingtalkcontact_1_0.Client(config); } /*** 获取用户个人信息* @param accessToken* @return* @throws Exception*/publicGetUserResponseBodygetUserinfo(StringaccessToken) throwsException { com.aliyun.dingtalkcontact_1_0.Clientclient=contactClient(); GetUserHeadersgetUserHeaders=newGetUserHeaders(); getUserHeaders.xAcsDingtalkAccessToken=accessToken; //获取用户个人信息,如需获取当前授权人的信息,unionId参数必须传meGetUserResponseBodyres=client.getUserWithOptions("me", getUserHeaders, newRuntimeOptions()).getBody(); returnres; } privateStringsaveSysUserAuto(OapiV2UserGetResponse.UserGetResponseuser) { List<UserRole>userRoleList=newArrayList(); //整理需要插入数据库字段Stringuserid=user.getUserid(); //判断当前用户是否已经插入过了LonguserId=null; SysUsersysUser=sysUserService.selectUserByDingDingUserid(userid); if (sysUser!=null) { userId=sysUser.getUserId(); }else { sysUser=newSysUser(); sysUser.setDingdingUserid(userid); sysUser.setAvatar(user.getAvatar()); sysUser.setUnionId(user.getUnionid()); sysUser.setPhonenumber(user.getMobile()); sysUser.setEmail(user.getEmail()); sysUser.setTitle(user.getTitle()); StringuserName=user.getName(); sysUser.setUserName(userName); //中文转拼音作为loginNameStringloginName=PinYinUtils.getPingYin(userName); //根据当前公司人员重名情况,最大重名6人,故此处设置最大重名为10StringBuildersb=newStringBuilder(loginName).append(","); for (inti=1; i<10; i++) { sb.append(loginName+String.valueOf(i)).append(","); } Stringloginnames=sb.toString(); //判断一下当前是否已经存在了loginnameSysUseruniqueuser=sysUserService.selectLastUserByLoginName(Convert.toStrArray(loginnames)); if (uniqueuser!=null) { //获取当前重名用户的序号Stringnumber=uniqueuser.getLoginName().replace(loginName, ""); //序号增加1在放回去拼接好inti=0; if (StringUtils.isNotEmpty(number)) { i=Integer.parseInt(number) +1; }else { //说明当前loginname还没有后续数字i=1; } sysUser.setLoginName(loginName+i); }else { sysUser.setLoginName(loginName); } sysUser.randomSalt(); //初始未编码前password为123456sysUser.setPassword(passwordService.encryptPassword(sysUser.getLoginName(), "123456", sysUser.getSalt())); sysUser.setCreateBy("扫码登录补充用户"); sysUser.setCreateTime(newDate()); sysUserService.insertSysUser(sysUser); userId=sysUser.getUserId(); //插入用户的角色,初始用户都是普通角色UserRoleur=newUserRole(); ur.setUserId(userId); if (Constants.ONE_KEY.equals(user.getUserid()) ||Constants.TWO_KEY.equals(user.getUserid())) { ur.setRoleId(1L); }else { ur.setRoleId(2L); } userRoleList.add(ur); } //插入用户的部门List<Long>deptIdList=user.getDeptIdList(); if (CollectionUtils.isNotEmpty(deptIdList)) { //插入部门之前需要清除之前的人员部门关系,以防钉钉部门变动而系统未感知intdele=sysUserDeptService.deleteSysUserDeptByUserId(userId); //插入人员部门关系表SysUserDeptuserDept=newSysUserDept(); userDept.setUserId(userId); for (Longdeptid : deptIdList) { userDept.setDeptId(deptid); userDept.setCreateBy("扫码登录补充用户"); userDept.setCreateTime(newDate()); sysUserDeptService.insertSysUserDept(userDept); } } //插入角色if (CollectionUtils.isNotEmpty(userRoleList)) { userRoleMapper.batchUserRole(userRoleList); } //登录系统returndoLoginSystem(sysUser); }
其中dingDingService.getUserIdByUnionIdV2(unionId)方法如下
/*** 根据unionId获取userId 2.0版本* @param unionId 当前钉钉用户在当前企业下的唯一识别码* @return*/publicOapiUserGetbyunionidResponse.UserGetByUnionIdResponsegetUserIdByUnionIdV2(StringunionId) { try { StringaccessToken=getAccessToken(); //根据unionId获取userIdDingTalkClientclient=newDefaultDingTalkClient("https://oapi.dingtalk.com/topapi/user/getbyunionid"); OapiUserGetbyunionidRequestreq=newOapiUserGetbyunionidRequest(); req.setUnionid(unionId); OapiUserGetbyunionidResponsersp=client.execute(req, accessToken); OapiUserGetbyunionidResponse.UserGetByUnionIdResponseresult=rsp.getResult(); returnresult; } catch (ApiExceptione) { e.printStackTrace(); } returnnull; }
dingDingService.getUserDetailByUserid(userIdByUnionIdV2.getUserid(), null)方法如下
/*** 查询用户详情* @param userid 钉钉userid* @param accessToken* @return*/publicOapiV2UserGetResponse.UserGetResponsegetUserDetailByUserid(Stringuserid, StringaccessToken) { try { if (StringUtils.isEmpty(accessToken)) { accessToken=getAccessToken(); } DingTalkClientclient=newDefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/get"); OapiV2UserGetRequestreq=newOapiV2UserGetRequest(); req.setUserid(userid); OapiV2UserGetResponsersp=client.execute(req, accessToken); OapiV2UserGetResponse.UserGetResponseresult=rsp.getResult(); returnresult; } catch (ApiExceptione) { e.printStackTrace(); returnnull; } }
PinYinUtils.java类如下
packagecom.dongao.project.utils; importnet.sourceforge.pinyin4j.PinyinHelper; importnet.sourceforge.pinyin4j.format.HanyuPinyinCaseType; importnet.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; importnet.sourceforge.pinyin4j.format.HanyuPinyinToneType; importnet.sourceforge.pinyin4j.format.HanyuPinyinVCharType; importnet.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; /*** @ClassName:PinYinUtils* @author:dongao* @date 2022/2/10 14:05*/publicclassPinYinUtils { /*** 中文转拼音* @param inputStr* @return*/publicstaticStringgetPingYin(StringinputStr) { if (inputStr==null||"".equals(inputStr)) { return""; } HanyuPinyinOutputFormatformat=newHanyuPinyinOutputFormat(); //UPPERCASE 大写 LOWERCASE 小写format.setCaseType(HanyuPinyinCaseType.LOWERCASE); //WITH_TONE_NUMBER 音标用数字 WITHOUT_TONE 无音标 WITH_TONE_MARK 直接用音标format.setToneType(HanyuPinyinToneType.WITHOUT_TONE); //WITH_U_AND_COLON 用u表示ü WITH_V 用v表示ü WITH_U_UNICODE 用ü表示üformat.setVCharType(HanyuPinyinVCharType.WITH_V); StringBuilderpYStr=newStringBuilder(); char[] input=inputStr.trim().toCharArray(); try { for (inti=0; i<input.length; i++) { if (Character.toString(input[i]).matches("[\\u4E00-\\u9FA5]+")) { pYStr.append(PinyinHelper.toHanyuPinyinStringArray(input[i], format)[0]); } elseif (!(input[i] ==' ')) { //过滤空格pYStr.append(input[i]); } } } catch (BadHanyuPinyinOutputFormatCombinatione) { e.printStackTrace(); } returnpYStr.toString(); } }
pom.xml增加
pom.xml涉及到的jar包有
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.6</version></dependency><dependency><groupId>com.aliyun</groupId><artifactId>dingtalk</artifactId><version>1.1.86</version></dependency><dependency><groupId>com.aliyun</groupId><artifactId>alibaba-dingtalk-service-sdk</artifactId><version>2.0.0</version></dependency><dependency><groupId>com.belerweb</groupId><artifactId>pinyin4j</artifactId><version>2.5.0</version></dependency>
那么到这里整个关于钉钉一键授权登录的页面代码以及后台逻辑代码也就写完了,下面看一下一键登录的效果
一键登录效果展示
登录页面点击【钉钉一键授权登录】
跳转到钉钉授权页面
点击【立即登录】
跳转到系统首页,这里文中的图片打码主要是由于内容涉及不方便展示,希望可以谅解,整体的流程和代码是可以参考的,如果有问题欢迎大家评论区留言讨论。