1. 程式人生 > >釘釘免登入

釘釘免登入

流程

首先需要理解一下釘釘的免登流程,借用官方文件的圖片:

免登入步奏

  1. 已知Corpld和CropSecret,獲取accessToken,即訪問令牌。
  2. 通過accessToken,獲取JsApiTicket,即JsApi的訪問許可(門票)。
  3. 按照規則在後臺由JsApiTicket、NonceStr、Timestamp、前端頁面Url生成字串,計算SHA1訊息摘要,即簽名Signature。
  4. 把AgentId、CorpId、Timestamp、NonceStr、Signature等引數傳遞到前臺,在前臺呼叫api,得到authCode,即授權碼。
  5. 根據授權碼,在前臺或後臺呼叫api,獲得userId,進而再根據userId,呼叫api獲取使用者詳細資訊

主要程式碼

DingServerController

using Common;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using WebApIs.BLL;
using WebApIs.Models;

namespace WebApIs.Controllers
{
/// <summary> /// /// </summary> public class DingServerController : ApiController { /// <summary> /// /// </summary> /// <returns></returns> public ResultJson GetLoginSign() { string corpId = "dinga85d93", corpSecret = "
D5r1G6cejOlZmEaB8PNlI9J5D"; string nonceStr = new Random().Next(1000, 10000).ToString(); //"helloDD";//todo:隨機 string NonceStr = nonceStr; string AccessToken = GetAccessToken(corpId, corpSecret); string ticket = GetJsApiTicket(AccessToken); TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); long timeStamp = Convert.ToInt64(ts.TotalSeconds); //?後端缺獲取簽名摘要 string url = "http://10.10.10.10:8084/Index.html";//訪問的頁面 Request.Url.ToString(); string signature = ""; int sta = DDev.GetSign(ticket, nonceStr, timeStamp, url, ref signature); return new ResultJson { agentId = "207623633", corpId = corpId, timeStamp = timeStamp, nonceStr = NonceStr, signature = signature }; } /// <summary> /// / /// </summary> /// <param name="code"></param> /// <returns></returns> // [HttpPost] public ResultJson GetCurrentUser(string code) { HROCPeopleBll ppbll = new HROCPeopleBll(); string corpId = "dinga85d9", corpSecret = "D5r1G6cejOlZmEaB8PNlI9J5"; string access_token = GetAccessToken(corpId, corpSecret); string tagUrl = "https://oapi.dingtalk.com/user/getuserinfo?access_token=" + access_token + "&code=" + code; string result = GetContents(tagUrl); var userModel = JsonConvert.DeserializeObject<UserInfo>(result); string ddid = userModel.userid; HROCPeople pp = new HROCPeople(); pp = ppbll.GetPeopleModel(ddid); userModel.BpmLoginName = pp.LoginName; userModel.BpmUserID = pp.ID; userModel.BpmUserName = pp.Name; return new ResultJson { DetailData = userModel }; // var dtmodel= JsonConvert.DeserializeObject<HROCPeople>(dt); //return new ResultJson { DetailData= pp.Name,data=pp.LoginName }; } /// <summary> /// /// </summary> /// <param name="DDID"></param> /// <returns></returns> public ResultJson GetCurrentUsers(string DDID) { HROCPeopleBll ppbll = new HROCPeopleBll(); HROCPeople hrp = ppbll.GetPeopleModel(DDID); return new ResultJson { DetailData = hrp }; } /// <summary> /// /// </summary> /// <param name="DDID"></param> /// <returns></returns> public string GetName(string DDID) { //return string.Format("姓名:{0}", Name); HROCPeopleBll ppbll = new HROCPeopleBll(); HROCPeople hrp = ppbll.GetPeopleModel(DDID); return string.Format("姓名:{0},登入名:{1},ID:{2} ", hrp.Name, hrp.LoginName, hrp.ID); //return new ResultJson { data = hrp.Name, signature= hrp.LoginName }; } //POST api/DingServer/GetCurrentUser? code = { code } /// <summary> /// /// </summary> /// <param name="corpId"></param> /// <param name="corpSecret"></param> /// <returns></returns> public string GetAccessToken(string corpId, string corpSecret) { string url = string.Format("https://oapi.dingtalk.com/gettoken?corpid={0}&corpsecret={1}", corpId, corpSecret); try { string response = GetContents(url); AccessTokenModel oat = Newtonsoft.Json.JsonConvert.DeserializeObject<AccessTokenModel>(response); if (oat != null) { if (oat.errcode == 0) { return oat.access_token; } } } catch (Exception ex) { throw; } return string.Empty; } public string GetJsApiTicket(string accessToken) { string url = string.Format("https://oapi.dingtalk.com/get_jsapi_ticket?access_token={0}", accessToken); try { string response = GetContents(url); JsApiTicketModel model = Newtonsoft.Json.JsonConvert.DeserializeObject<JsApiTicketModel>(response); if (model != null) { if (model.errcode == 0) { return model.ticket; } } } catch (Exception ex) { throw ex; } return string.Empty; } public static string GetContents(string url) { WebRequest request = HttpWebRequest.Create(url); WebResponse response = request.GetResponse(); Stream stream = response.GetResponseStream(); StreamReader reader = new StreamReader(stream); string content = reader.ReadToEnd(); return content; } } public class AccessTokenModel { public string access_token { get; set; } public int errcode { get; set; } public string errmsg { get; set; } } public class JsApiTicketModel { public string ticket { get; set; } public int errcode { get; set; } public string errmsg { get; set; } } public class UserIdModel { public string userid { get; set; } public int errcode { get; set; } public string errmsg { get; set; } } public class UserDetailInfo { public string userid { get; set; } public int errcode { get; set; } public string username { get; set; } } }
View Code

HROCPeople

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace WebApIs.Models
{
    public class HROCPeople
    {
        public string ID { get; set; }
        public int IntID { get; set; }
        public string JobID { get; set; }
        public string CreateTime { get; set; }
        public string Name { get; set; }

        public string LoginName { get; set; }
        public string CompanyID { get; set; }
        public string DepartmentID { get; set; }
        //釘釘號 格式:{"DING":"211202322424329696"}
        public string other1 { get; set; }
    }
}
View Code

釘釘幫助類

using System;
using System.Text;
using System.Security.Cryptography;
using System.Collections;

namespace Common
{
    public static class DDev
    {
       
        public static int GenSigurate(string jsapi_ticket, string noncestr, string sTimeStamp, string url, ref string signature)
        {


           string assemble = string.Format("jsapi_ticket={0}&noncestr={1}&timestamp={2}&url={3}", jsapi_ticket, noncestr, sTimeStamp, url);
            SHA1 sha;
            ASCIIEncoding enc;
            string hash = "";
            try
            {
                sha = new SHA1CryptoServiceProvider();
                enc = new ASCIIEncoding();
                byte[] dataToHash = enc.GetBytes(assemble);
                byte[] dataHashed = sha.ComputeHash(dataToHash);
                hash = BitConverter.ToString(dataHashed).Replace("-", "");
                hash = hash.ToLower();
            }
            catch (Exception)
            {
                return 2;
            }
            signature = hash;
            return 0;

        }

        public static int GetSign(string ticket, string nonceStr, long timeStamp, string url, ref string signature)
        {
            String plain = string.Format("jsapi_ticket={0}&noncestr={1}&timestamp={2}&url={3}", ticket, nonceStr, timeStamp, url);
            try
            {
                byte[] bytes = Encoding.UTF8.GetBytes(plain);
                byte[] digest = SHA1.Create().ComputeHash(bytes);
                string digestBytesString = BitConverter.ToString(digest).Replace("-", "");
                signature = digestBytesString.ToLower();
                return 1;
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        /// <summary>
        /// 獲取時間戳timestamp(當前時間戳,具體值為當前時間到1970年1月1號的秒數)
        /// </summary>
        /// <returns></returns>
        public static string GetTimeStamp()
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds).ToString();
        }
        /// <summary>
        /// 字典排序
        /// </summary>
        public class DictionarySort : System.Collections.IComparer
        {
            public int Compare(object oLeft, object oRight)
            {
                string sLeft = oLeft as string;
                string sRight = oRight as string;
                int iLeftLength = sLeft.Length;
                int iRightLength = sRight.Length;
                int index = 0;
                while (index < iLeftLength && index < iRightLength)
                {
                    if (sLeft[index] < sRight[index])
                        return -1;
                    else if (sLeft[index] > sRight[index])
                        return 1;
                    else
                        index++;
                }
                return iLeftLength - iRightLength;

            }
        }
    }
}
View Code

前端程式碼

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>釘釘服務介面除錯</title>
    <!--<script type="text/javascript" src="script/jquery.min.js"></script>
    <script type="text/javascript" src="script/bootstrap.min.js"></script>-->
    <script src="//cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
    <script type="text/javascript" src="http://g.alicdn.com/dingding/open-develop/1.5.1/dingtalk.js"></script>
    <link type="text/css" rel="stylesheet" href="content/bootstrap.css" media="screen" />
    <style>
        body {
            margin: 20px 20px;
        }
    </style>
</head>
<body>


    <div class="panel panel-primary">

        <div class="panel-heading">
            <h3 class="panel-title">使用者介面</h3>
        </div>
        <input id="notice" type="text" />
        <div class="panel-body">
            <div class="method-margin col-md-12">
                <div style="margin-bottom:5px;">
                    <button type="button" class="btn btn-default" data-loading-text="正在請求..." id="getUserDetail">獲取使用者詳情</button>


                </div>
                <div class="method-output-padding">
                    <div class="logs-margin alert alert-danger alert-dismissible" role="alert" name="showErrorAlert">
                        <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
                        <span name="errorText"></span>
                    </div>
                    <div class="logs-margin alert alert-success alert-dismissible" role="alert" name="showInfoAlert">
                        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                            <span aria-hidden="true">×</span>
                        </button>
                        <span name="successText"></span>

                    </div>
                </div>
            </div>
        </div>
    </div>




    <script type="text/javascript">

        function login1(id) {
            $.ajax({
                url: 'http://10.10.10.10:8081/api/DingServer/GetName',
                type: 'get',
                //  dataType: 'JSON',
                data: { "DDID": id },
                success: function (data) {
                   // alert(JSON.stringify(data))
                    alert(data)
                    //var DDID = data.DetailData.userid;
                    //alert(DDID)
                    //login1(data.DetailData.userid)
                },
                error: function (data) {
                   // alert(JSON.stringify(data))
                }
            })
        }

        //function login1(id) {
        //    $.ajax({
        //        url: 'http://10.10.10.10:8081/api/DingServer/GetCurrentUsers',
        //        type: 'get',
        //        //  dataType: 'JSON',
        //        data: { DDID: id },
        //        success: function (data) {
        //            alert(data)
        //            //var DDID = data.DetailData.userid;
        //            //alert(DDID)
        //            //login1(data.DetailData.userid)
        //        },
        //        error: function (data) {
        //            alert(JSON.stringify(data))
        //        }
        //    })
        //}

        function login(code) {
            $.ajax({
                url: 'http://10.10.10.10:8081/api/DingServer/GetCurrentUser',
                type: 'GET',
              //  dataType: 'JSON',
                data: {code:code },
                success: function (data, status, xhr) {
                    //alert(JSON.stringify(data))
                    alert(data.DetailData.BpmUserID + "-" + data.DetailData.BpmUserName + "-" + data.DetailData.BpmLoginName)
                },
                error: function (data) {
                    alert(JSON.stringify(data))
                }
            })
        }

        //獲取簽名摘要??
        $(document).ready(function () {
            $.ajax({
                url: "http://10.10.10.10:8081/api/DingServer/GetLoginSign",
                type: 'GET',
                success: function (data, status, xhr) {
                     if (data.code != 0) {
                    } else {
                        var str = JSON.stringify(data);
                       // alert(str);
                        dd.config({
                            agentId: data.agentId,
                            corpId: data.corpId,
                            timeStamp: data.timeStamp,
                            nonceStr: data.nonceStr,
                            signature: data.signature,
                            jsApiList: ['runtime.info', 'biz.contact.choose',
                                    'device.notification.confirm', 'device.notification.alert',
                                    'device.notification.prompt', 'biz.ding.post',
                                    'biz.util.openLink']
                        });

                        dd.error(function (err) {
                            alert('dd error: ' + JSON.stringify(err))
                        })

                        dd.ready(function () {
                            dd.runtime.permission.requestAuthCode({
                                corpId: data.corpId,
                                onSuccess: function (result) {
                                    alert(JSON.stringify(result))
                                    login(result.code)
                                }
                            })
                        })


                    }
                },

                    error: function (data) {
                        console.log('err:', data)
                    }
            })

        })



    </script>
</body>
</html>
View Code

 

釘釘管理員配置應用

釘釘免登就是這樣,只要弄懂了就會覺得其實不難。感謝閱讀。