• springboot实现第三方钉钉扫码登录


     本篇博客主要作为本人的日记,如果各位博友对以下内容有所疑问欢迎留言探讨。

    一、准备工作

    1、钉钉开放平台注册登录:

            登录地址:https://open.dingtalk.com/

    2、注册登录成功后选择你加入的组织

     3、创建应用 

    4、相关权限开通(权限开通都是免费) 

     5、设置扫描成功后的回调域名

      如果开发者没有域名可以随便写一个域名,在本地host中配置对应的域名即可

     

     6、本地host文件配置域名

      host文件路径为:C:\Windows\System32\drivers\etc\host,打开host文件添加以上输入的回调域名,本人写的回调地址为“www.chenyuanbo.com”,配置如下所示:

    7、开发环境下配置好内网穿透

      (1)登录natApp官网注册;https://natapp.cn/,在右上角点击“客户端下载”,下载对应的natApp客户端,登录成功后的界面如下,authToken用于启动natApp

     (2)启动内网穿透

      打开下载好的natApp,运行natapp.exe,输入命令:natapp -authtoken="NatApp的隧道authtoken",出现以下界面说明内网穿透启动已成功

    二、功能实现思路:

    1、获取钉钉二维码界面(即下方:dingdingLogin方法)

    2、扫二维码成功后进入回调方法,获取code。

    3、请求获取accessToken

    4、根据code和accessToken获取用户信息(含用户openId)

    5、根据用户openId去自己系统的用户表中查询是否存在对应的用户,如果存在则登录成功,跳转至系统首页

    三、功能开发

      1、maven坐标:

         <dependency>
                <groupId>com.aliyun</groupId>
                <artifactId>dingtalk</artifactId>
                <version>1.2.43</version>
            </dependency>
            <dependency>
                <groupId>com.aliyun</groupId>
                <artifactId>alibaba-dingtalk-service-sdk</artifactId>
                <version>2.0.0</version>
            </dependency>

      2、具体代码实现

    package com.cyb.sso.server.controller;
    
    import com.dingtalk.api.DefaultDingTalkClient;
    import com.dingtalk.api.DingTalkClient;
    import com.dingtalk.api.request.OapiGettokenRequest;
    import com.dingtalk.api.request.OapiSnsGetuserinfoBycodeRequest;
    import com.dingtalk.api.response.OapiGettokenResponse;
    import com.dingtalk.api.response.OapiSnsGetuserinfoBycodeResponse;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    
    /**
     *@ClassName UnionLoginController
     *@Description 联合登录控制层
     *@Author cyb
     *@Date 2022/1/25 23:06
     */
    @Controller
    @RequestMapping("/unionLogin")
    @Slf4j
    public class UnionLoginController {
    
        /***
         * 钉钉APPKey或SuiteKey
         */
        private static final  String DING_TALK_APP_ID="dingrd9jvv0i2z0eu62q";
    
        /***
         * 钉钉SuiteSecret或appSecret
         */
        private static final String DING_TALK_SECRET ="HkOsehRYCwhJBg-nChBGdxAg2eoLA9A3T1ykbR1kR4HU5XzrO_D79s8Y6BJ-Pjzy";
    
        /***
         * 钉钉扫码后回调地址
         * http://www.chenyuanbo.com:8080/xxl-sso-server/unionLogin/dingdingCallback
         */
        private static final String DING_TALK_CALL_BACK_URL = "http%3A%2F%2Fwww.chenyuanbo.com%3A8080%2Fxxl-sso-server%2FunionLogin%2FdingdingCallback";
    
        /***
         * 获取accessToken请求URL
         */
        private static final String getTokenUrl ="https://oapi.dingtalk.com/gettoken";
    
        /***
         * 获取用户详情URL
         */
        private static final String getUserInfoUrl= ":https://oapi.dingtalk.com/sns/getuserinfo_bycode";
    
        /***
         * 获取钉钉联合登录二维码
         * @return 钉钉二维码
         */
        @ResponseBody
        @RequestMapping("/dingdingLogin")
        public Object dingdingLogin() {
            String time = String.valueOf(System.currentTimeMillis());//产生一个当前的毫秒
            StringBuilder stringBuilder = new StringBuilder();
            String result="";
            stringBuilder
                    .append("https://oapi.dingtalk.com/connect/qrconnect?appid=")
                    .append(DING_TALK_APP_ID)//APP_ID
                    .append("&response_type=")
                    .append("code")//code
                    .append("&scope=")
                    .append("snsapi_login")//snsapi_login
                    .append("&state=")
                    .append(time)
                    .append("&redirect_uri=")
                    .append(DING_TALK_CALL_BACK_URL);//回调地址
            try {
                result = stringBuilder.toString();
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
            return result;
        }
    
        /***
         * 扫码后的回调方法
         * @param code 钉钉扫码返回的code
         * @return
         */
        @RequestMapping(value="/dingdingCallback", produces="text/html; charset=utf-8")
        public Object getUserInfo(String code) {
    
           log.info("进入回调");
           //1、获取accesstoken
            String accessToken = getAccessToken();
            if(StringUtils.isEmpty(accessToken)){
                return "未获取到accessToken,跳转到登录页";
            }
            //2、根据accessToken和code获取用户OpenId
            String openId = getPersistentCode(accessToken, code);
            if(StringUtils.isEmpty(openId)){
                return "未获取到用户OpenId,跳转到登录页使用账户密码登录";
            }
            //3、根据openId查询数据库用户表,如果查询到用户则登录成功,未查询到则返回到登录首页使用账号密码登录并进行绑定钉钉openId
    
            return null;
        }
    
    
         /**
          * @method  获取accesstoken
          * @description 获取accesstoken
          * @date: 2022/1/26 22:00
          * @author: cyb
          * @return 钉钉accessToken
          */
        public String getAccessToken() {
            try {
            DingTalkClient clientDingTalkClient = new DefaultDingTalkClient(getTokenUrl);
            OapiGettokenRequest request = new OapiGettokenRequest();
            // 填写步骤一创建应用的Appkey
            request.setAppkey(DING_TALK_APP_ID);
            // 填写步骤一创建应用的Appsecret
            request.setAppsecret(DING_TALK_SECRET);
            request.setHttpMethod("GET");
            OapiGettokenResponse response =clientDingTalkClient.execute(request);
            if(response.getErrcode() == 0){
                return response.getAccessToken();
            }
            log.info("获取accessToken失败:{}",response.getMsg());
            }catch (Exception e){
                log.error("获取accessToken失败:",e);
            }
            return null;
        }
    
         /**
          * @method  getPersistentCode
          * @description 获取用户openId
          * @date: 2022/1/26 22:08
          * @author: cyb
          * @param accessToken 用户的accessToken
          * @param code 扫码返回的code
          * @return openId
          */
        public String getPersistentCode(String accessToken,String code)  {
            try {
                DefaultDingTalkClient  client = new DefaultDingTalkClient(getUserInfoUrl);
                OapiSnsGetuserinfoBycodeRequest req = new OapiSnsGetuserinfoBycodeRequest();
                req.setTmpAuthCode(code);
                OapiSnsGetuserinfoBycodeResponse response = client.execute(req,DING_TALK_APP_ID,DING_TALK_SECRET);
                if(0 != response.getErrcode()){
                    return null;
                }
                OapiSnsGetuserinfoBycodeResponse.UserInfo userInfo = response.getUserInfo();
                if(null != userInfo){
                    return  userInfo.getOpenid();
                }
            }catch (Exception e){
                log.error("获取用户信息失败:",e);
            }
            return null;
        }
    
    
    }

    以上则为钉钉扫码登录的主要流程,如有其他功能需求,可以查阅官网的文档说明,以扫码登录为例,访问网站:https://open.dingtalk.com/document/orgapp-server/obtain-the-user-information-based-on-the-sns-temporary-authorization。转载请说明出处

  • 相关阅读:
    vue 中的键盘事件
    红米k40刷类原生系统
    (历史) 1960s,大家争先在共享内存上实现原子性 (互斥) 但几乎所有的实现都是错的,直到 Dekker's Algorithm,还只能保证两个线程的互斥
    Go Memory Model 内存模型 同步 goroutine
    理解并发程序执行 (Peterson算法、模型检验与软件自动化工具
    源码 连接池 设计
    Thread Exception Captured Application Crash Report
    Check if the context is expired.
    A Quick Guide to Go's Assembler
    敏感问题调查 干扰变量 抛硬币
  • 原文地址:https://www.cnblogs.com/chenyuanbo/p/15848567.html
Copyright © 2020-2023  润新知