釘釘掃碼登陸的實現 與OAUTH2.0

 

1.1 傳統的登陸

舉一個例子:有一個"雲沖印"的網站,能夠將用戶儲存在Google的照片,沖印出來。用戶爲了使用該服務,必須讓"雲沖印"讀取本身儲存在Google上的照片。數據庫

問題是隻有獲得用戶的受權,Google纔會贊成"雲沖印"讀取這些照片。那麼,"雲沖印"怎樣得到用戶的受權呢?
傳統方法是,用戶將本身的Google用戶名和密碼,告訴"雲沖印",後者就能夠讀取用戶的照片了。這樣的作法有如下幾個嚴重的缺點json

傳統登陸的缺點

(1)"雲沖印"爲了後續的服務,會保存用戶的密碼,這樣很不安全。
(2)Google不得不部署密碼登陸,而咱們知道,單純的密碼登陸並不安全。
(3)"雲沖印"擁有了獲取用戶儲存在Google全部資料的權力,用戶無法限制"雲沖印"得到受權的範圍和有效期。
(4)用戶只有修改密碼,才能收回賦予"雲沖印"的權力。可是這樣作,會使得其餘全部得到用戶受權的第三方應用程序所有失效。
(5)只要有一個第三方應用程序被破解,就會致使用戶密碼泄漏,以及全部被密碼保護的數據泄漏。c#

1.2 OAUTH

OAUTH協議爲用戶資源的受權提供了一個安全的、開放而又簡易的標準。與以往的受權方式不一樣之處是OAUTH的受權不會使第三方觸及到用戶的賬號信息(如用戶名與密碼),
即第三方無需使用用戶的用戶名與密碼就能夠申請得到該用戶資源的受權,所以OAUTH是安全的。oAuth是Open Authorization的簡寫。api

 

OAUTH原理

我在圖上分了四個步驟,下面是四步的講解:
  第一步:用戶訪問第三方網站,好比:就是你須要使用QQ進行登陸的網站;
  第二步:你點擊QQ登陸後,第三方網站將會鏈接並進行請求,好比:你點擊登陸後,第三方網站會跳轉到QQ平臺,提示你進行登陸;
  第三步:你要進行受權第三方網站對你的信息訪問的一個權限,好比:當你QQ登陸成功後,QQ會提示你,是否受權第三方Web訪問你的用戶基本信息或其餘的資源信息,這時你點擊受權便可;
  第四步:受權後,第三方Web便可訪問你剛纔受權的資源信息,好比:你的QQ基本信息-頭像、暱稱、性別等。安全

OAUTH2.0 認證流程

第一步:首先直接跳轉至用戶受權地址,即圖示 Request User Url ,提示用戶進行登陸,並給予相關資源受權,獲得惟一的Auth code,這裏注意的是code只有10分鐘的有效期  
第二步:獲得受權code後,這一步就是請求access token,經過 圖示 Request access url ,生成獲得數據Token;
 第三步:經過Access Token請求OpenID,OpenID是用戶在此平臺的惟一標識,經過圖示 Request info url 請求,而後獲得OpenID;
 第四步:經過第二步獲得的數據Token、第三步獲得的OpenID及相關API,進行請求,獲取用戶受權資源信息。服務器

釘釘登陸的實現

釘釘登陸實現的原理其實就是用的OAUTH2.0app

要讓你的app實現釘釘的登陸獲取登錄者相關的信息,你須要作一塊兒操做:網站

1.首先你須要登陸釘釘管理員帳號,this

(https://open-doc.dingtalk.com/doc2/detail.htm?treeId=168&articleId=104881&docType=1)url

這是詳細操做獲取地址網址,

2 c#實現登陸

  1  public ActionResult Index(string url)
  2         {
  3             var s = Request.Url.ToString();
  4             s = s.Replace("code=", "&");
  5             s = s.Replace("&state=", "&");
  6             if (s.Contains("STATE"))
  7             {
  8                 try
  9                 {
 10                     var code = s.Split('&')[1].ToString();
 11                     var access_token = "";
 12 
 13                     #region 使用appid及appSecret訪問以下接口,獲取accesstoken
 14 
 15                     var uriString = "";
 16                    
 17                      if (s.Contains("服務器ip地址"))
 18                     {
 19                         uriString = @"https://oapi.dingtalk.com/sns/gettoken?appid=dingoaycgdqrrmcvvgde99&appsecret=eKBFq0-0yoWyg9jCWh-K6HiDVh9jP0_0lyOqGhDYfQ8HWb7ZlNUiGnP8JOOP2pSL";
 20                     }
 21                     var uri = new Uri(uriString);
 22                     var req = HttpWebRequest.Create(uri) as HttpWebRequest;
 23                     //設置通用的請求屬性
 24                     req.Method = "get";
 25                     req.Host = "oapi.dingtalk.com";
 26                     req.ContentType = "application/Json";
 27                     req.Timeout = 1000 * 30;
 28                     var rsp = this.RequestHttp(req);
 29                     using (Stream stream = rsp.GetResponseStream())
 30                     {
 31                         using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
 32                         {
 33                             var text = reader.ReadToEnd();
 34                             access_token = text.Split(',')[1].ToString().Split(':')[1].ToString();
 35                         }
 36                     }
 37 
 38                     #endregion
 39 
 40                     #region 根據code 和 accesstoken 獲取當前釘釘用戶受權給你的持久受權碼
 41 
 42                     var uriString2 = "https://oapi.dingtalk.com/sns/get_persistent_code?access_token=" + access_token;
 43                     uriString2 = uriString2.Replace("\"", "");
 44                     var uri2 = new Uri(uriString2);
 45                     var req2 = HttpWebRequest.Create(uri2) as HttpWebRequest;
 46                     req2.Method = "Post";
 47                     req2.Accept = "*/*";
 48                     req2.Host = uri2.Authority;
 49                     req2.ContentType = "application/Json";
 50 
 51                     var jsonData = "{\"tmp_auth_code\"" + ":\"" + code + "\"}";
 52 
 53                     byte[] cont = Encoding.UTF8.GetBytes(jsonData);
 54 
 55 
 56                     req2.ContentLength = cont.Length;
 57                     Stream reqStream2 = req2.GetRequestStream();
 58                     reqStream2.Write(cont, 0, cont.Length);
 59 
 60                     var rsp2 = this.RequestHttp(req2);
 61                     var persistentCode = "";
 62                     using (Stream stream2 = rsp2.GetResponseStream())
 63                     {
 64                         using (StreamReader reader = new StreamReader(stream2, Encoding.UTF8))
 65                         {
 66                             var text = reader.ReadToEnd();
 67                             persistentCode = text;
 68                         }
 69                     }
 70 
 71                     #endregion
 72 
 73                     #region 經過永久受權碼,獲取該用戶受權的SNS_TOKEN,此token的有效時間爲2小時,重複獲取不會續期
 74 
 75                     var uriString3 = "https://oapi.dingtalk.com/sns/get_sns_token?access_token=" + access_token;
 76                     uriString3 = uriString3.Replace("\"", "");
 77                     var uri3 = new Uri(uriString3);
 78                     var req3 = HttpWebRequest.Create(uri3) as HttpWebRequest;
 79                     req3.Method = "Post";
 80                     req3.Accept = "*/*";
 81                     req3.Host = uri3.Authority;
 82                     req3.ContentType = "application/Json";
 83 
 84                     byte[] cont3 = Encoding.UTF8.GetBytes(persistentCode);
 85 
 86 
 87                     req3.ContentLength = cont3.Length;
 88                     Stream reqStream3 = req3.GetRequestStream();
 89                     reqStream3.Write(cont3, 0, cont3.Length);
 90 
 91                     var rsp3 = this.RequestHttp(req3);
 92                     var sns_token = "";
 93                     using (Stream stream3 = rsp3.GetResponseStream())
 94                     {
 95                         using (StreamReader reader = new StreamReader(stream3, Encoding.UTF8))
 96                         {
 97                             var text = reader.ReadToEnd();
 98                             sns_token = text.Split(',')[2].ToString().Split(':')[1].ToString();
 99                         }
100                     }
101 
102                     #endregion
103 
104                     #region 在得到釘釘用戶的SNS_TOKEN後,經過如下請求獲取該用戶的我的信息
105 
106                     var uriString4 = "https://oapi.dingtalk.com/sns/getuserinfo?sns_token=" + sns_token;
107                     uriString4 = uriString4.Replace("\"", "");
108                     var uri4 = new Uri(uriString4);
109                     var req4 = HttpWebRequest.Create(uri4) as HttpWebRequest;
110                     req4.Method = "get";
111                     req4.Accept = "*/*";
112                     req4.Host = uri4.Authority;
113                     req4.ContentType = "application/Json";
114 
115                     var rsp4 = this.RequestHttp(req4);
116                     var userName = "";
117                     using (Stream stream4 = rsp4.GetResponseStream())
118                     {
119                         using (StreamReader reader = new StreamReader(stream4, Encoding.UTF8))
120                         {
121                             var text = reader.ReadToEnd();
122                             userName = text.Split(':')[5].ToString().Split(',')[0].ToString();
123                             userName = userName.Substring(1, userName.Length - 2);//去掉引號
124                         }
125                     }
126 
127                     #endregion
128 
129                     ViewBag.UserName = userName;
130                     var repo = RF.Concrete<DBMUserRepository>();
131                     var user = repo.GetByName(userName);
132                     if (user.Count == 0)
133                     {
134                         DBMUser item = new DBM.DBMUser();
135                         item.Name = userName;
136                         RF.Save(item);
137                     }
138 
139                     ///當數據庫沒有該用戶的時候,數據庫爲該用戶添加數據
140                     var newUser = repo.GetByName(userName)[0];
141                     DBMContext.CurrentUser = newUser;
142                     DBMContext.IsAdmin = newUser.IsAdmin;
143                     return View();
144                 }
145                 catch (Exception e)
146                 {
147                     return null;
148                 }
149             }
150             else
151             {
152                 ViewBag.UserName = "error1";
153                 return View();
154             }
155         }

 

 這樣就OK了。

相關文章
相關標籤/搜索