当前位置: 首页 > article >正文

SpingBoot-Vue 前后端分离—实现钉钉免登功能(2025)

一、需求分析

        要实现钉钉免登功能,需要按照钉钉开放平台所提供步骤,进一步可以细分成以下操作:

    A [用户访问应用] --> B [获取临时授权码(code)]
    B --> C [应用服务器请求access_token]
    C --> D [钉钉服务器返回access_token]
    D --> E [应用服务器请求用户信息]
    E --> F [钉钉服务器返回用户信息]
    F --> G [应用服务器处理用户信息]
    G --> H [用户登录成功]   

总结过后,具体免登流程如下:

  1. 调用本接口获取免登授权码。
  2. 调用获取应用的 Access Token接口,获取应用访问凭证。
  3. 调用通过免登码获取用户信息接口,获取用户userid。
  4. 调用查询用户详情接口,获取用户信息。

二、具体实现

①、前端实现

 以某信息确认系统首页为例,若是钉钉环境下,直接实现免登操作,若不是钉钉环境,则实现账号和密码的方式进行登录:

<template>
  <div>
    <div class="login">
      <p>XXX信息确认系统</p>
      <div class="loginContent">
      <div class="fromuseruser">
        <input type="text" v-model="user_name" placeholder="请输入账号" />
      </div>
      <div class="frompassword">
        <input
          type="password"
          v-model="user_password"
          placeholder="请输入密码"
        />
      </div>
      </div>
      <div class="submit">
        <van-button
          type="primary"
          :round="true"
          loading-text="加载中..."
          size="normal"
          style="width:4.6rem"
          text="登 录"
          @click="submit"
        ></van-button>
      </div>
    </div>
  </div>
</template>

<script>
import * as dd from 'dingtalk-jsapi'
import { Notify } from 'vant'
import {UserLogin} from "@/api/request.js";
export default {
  data() {
    return {
        user_name:"",
        user_password: "",
        code: null,
    };
  },
  mounted(){
    // this.ddFun();
    window.addEventListener('keydown',this.keyDown)

  },
  methods:{
    ddFun(){
      let _this = this
      // corpId 在后台 -基本信息-开发信息-企业自用账户信息 下查看
      let corpId = ''
      dd.ready(()=> {
        // dd.ready参数为回调函数,在环境准备就绪时触发,jsapi的调用需要保证在该回调函数触发后调用,否则无效。
        dd.runtime.permission.requestAuthCode({
          corpId:corpId,
          onSuccess: result => {
            _this.code = result.code;
            let param = {
              code: _this.code,
            };
            _this.login(param);
          },
          onFail: err => {
            alert("dd error: " + JSON.stringify(err));
          },
        });
      });
    },
    submit(){
      if(this.user_name == '' || this.user_password == ''){
        Notify({
          type: "danger",
          message: `账号或密码不能为空`,
        });
        return;
      }
      let u_pass = this.$encruption(this.user_password) //对密码进行签名加密
      let param = {
        'uN':this.user_name,
        'pW':u_pass
        // 'pW':this.user_password
      };
       // this.login(param)
      UserLogin(param).then((res) => {
        console.log('登录Res',res);
        if (res.result == 1) {
          sessionStorage.setItem('tel',JSON.stringify(res.data.tel))
          sessionStorage.setItem('token',JSON.stringify(res.data.token))

          if(res.data.auth == 2){
            this.$router.push("/sensorjxpro/web/jxensure");
          }else if(res.data.auth == 1){
            this.$router.push("/sensorjxpro/web/staff/mobileweb");
          }
        } else {
          Notify({
            type: "danger",
            message: `${res.data.msg}`+ ','+`${res.data.data}`,
          });
        }
      })
    },
    // 回车登录
    keyDown(e){
      if(e.keyCode === 13){
        this.submit()
      }
    }

  },
  deactivated() {
    this.user_name = "";
    this.user_password = "";
    this.code = null;
  },
  destroyed(){
    window.removeEventListener('keydown',this.keyDown,false)
  }
}
</script>

<style lang="scss" scoped>
@import '@/style/login/login.scss'
</style>

关键钉钉免登的实现步骤主要是,通过 dd.runtime.permission.requestAuthCode 将code 传递给后端,后端进行解析,至此第一步,调用本接口获取免登授权码完成(前端也主要负责这一部分)

ddFun(){
      let _this = this
      // corpId 在后台 -基本信息-开发信息-企业自用账户信息 下查看
      let corpId = ''
      dd.ready(()=> {
        // dd.ready参数为回调函数,在环境准备就绪时触发,jsapi的调用需要保证在该回调函数触发后调用,否则无效。
        dd.runtime.permission.requestAuthCode({
          corpId:corpId,
          onSuccess: result => {
            _this.code = result.code;
            let param = {
              code: _this.code,
            };
            _this.login(param);
          },
          onFail: err => {
            alert("dd error: " + JSON.stringify(err));
          },
        });
      });
    },

②、后端实现

        将前端传来的code,调用获取应用的 Access Token接口,获取应用访问凭证。调用通过免登码获取用户信息接口,获取用户userid。调用查询用户详情接口,获取用户信息。并最终在数据库中根据name查询,二次确认,并将得到的name信息返回给前端。至此完成钉钉免登的全部流程。

subgraph 钉钉服务器
        D[返回access_token]
        F[返回用户信息]
    end

    subgraph 应用服务器
        C[请求access_token]
        E[请求用户信息]
        G[处理用户信息]
    end

/**
     * 用户登陆
     * http://localhost:8080/user/login
     * 0、判断是否包含code,包含进行钉钉免登陆方法;
     *
     * 1、依据姓名密码查找user;
     * 2、使用jwtUtils生成token,token载体内容为 name、tel
     * 3、将LoginVo 赋值作为响应实体类的响应数据(data)
     *
     * @return RespondDto
     */
    @Override
    public RespondDto userLogin(InParam inParam) {

        User user;
        if(inParam.getCode() == null){
            log.info("userLogin方法成功调用 userName:{}", inParam.getUN());
            inParam.setPW(rsaUtils.priKeyDecode(inParam.getPW()));
            user = loginMapper.selectUser(inParam.getUN(), inParam.getPW());

            log.info("userLogin查找方法调用完成,user:{}", user);
        }else{
            user = ddLogin(inParam);
        }
        if (user != null) {
            LoginVo loginVo = new LoginVo();

            loginVo.setName(user.getUserName());
            loginVo.setTel(user.getTel());
            loginVo.setToken(jwtUtils.tokenMaker(user));
            loginVo.setAuth(user.getAuth());

            return new RespondDto(ResultCode.OK,"登录成功",loginVo);
        } else {
            return new RespondDto(ResultCode.USER_NONE, "登陆失败");
        }
    }

    /**钉钉免登陆
     * 1、获取 accessToken;
     * 2、获取用户信息,截取到name;
     * 3、用name查找 user;*/
    private User ddLogin(InParam inParam) {
        String code = inParam.getCode();

        // 获取access_token
        String accessToken = HttpHelper.getAccess_Token(appkey, appsecret);

        //不要获取userid,  不可与以下代码同用;
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/getuserinfo");
        OapiV2UserGetuserinfoRequest req = new OapiV2UserGetuserinfoRequest();
        req.setCode(code);
        OapiV2UserGetuserinfoResponse rsp = null;
        try {
            rsp = client.execute(req, accessToken);
        } catch (ApiException e) {
            e.printStackTrace();
        }

        System.out.println(rsp.getBody());
        String body = rsp.getBody();
        String name = body.substring(body.indexOf("name\":\""),body.indexOf("\",\"sys")).substring(7);
        System.out.println(name);

        User user = loginMapper.selectUserByName(name);
        return user;
    }


http://www.kler.cn/a/552586.html

相关文章:

  • 【Spring+MyBatis】_图书管理系统(中篇)
  • c# -01新属性-模式匹配、弃元、析构元组和其他类型
  • spark大数据分析
  • python-leetcode-最小路径和
  • vue中使用富文本编辑器
  • SpringBoot速成(14)文件上传P23-P26
  • GIT:如何合并已commit的信息并进行push操作
  • 【达梦数据库】dblink连接[SqlServer/Mysql]报错处理
  • Edge浏览器清理主页
  • Copilot Next Edit Suggestions(预览版)
  • nodejs:express + js-mdict 网页查询英汉词典,能显示图片
  • 【Java 面试 八股文】并发编程篇
  • The First项目报告:重塑链上游戏生态,解读B3 Base的双赢局面
  • Pytorch实现之粒子群优化算法在GAN中的应用
  • 一周学会Flask3 Python Web开发-post请求与参数获取
  • TCP通讯-客户端链接
  • mysql 学习16 视图,存储过程,存储函数,触发器
  • MySQL中的事务隔离级别有哪些?
  • 【嵌入式Linux应用开发基础】进程实战开发
  • WPF创建自定义类和控件及打包成dll引用