舉一個例子:有一個"雲沖印"的網站,能夠將用戶儲存在Google的照片,沖印出來。用戶爲了使用該服務,必須讓"雲沖印"讀取本身儲存在Google上的照片。數據庫
問題是隻有獲得用戶的受權,Google纔會贊成"雲沖印"讀取這些照片。那麼,"雲沖印"怎樣得到用戶的受權呢?
傳統方法是,用戶將本身的Google用戶名和密碼,告訴"雲沖印",後者就能夠讀取用戶的照片了。這樣的作法有如下幾個嚴重的缺點json
(1)"雲沖印"爲了後續的服務,會保存用戶的密碼,這樣很不安全。
(2)Google不得不部署密碼登陸,而咱們知道,單純的密碼登陸並不安全。
(3)"雲沖印"擁有了獲取用戶儲存在Google全部資料的權力,用戶無法限制"雲沖印"得到受權的範圍和有效期。
(4)用戶只有修改密碼,才能收回賦予"雲沖印"的權力。可是這樣作,會使得其餘全部得到用戶受權的第三方應用程序所有失效。
(5)只要有一個第三方應用程序被破解,就會致使用戶密碼泄漏,以及全部被密碼保護的數據泄漏。c#
OAUTH協議爲用戶資源的受權提供了一個安全的、開放而又簡易的標準。與以往的受權方式不一樣之處是OAUTH的受權不會使第三方觸及到用戶的賬號信息(如用戶名與密碼),
即第三方無需使用用戶的用戶名與密碼就能夠申請得到該用戶資源的受權,所以OAUTH是安全的。oAuth是Open Authorization的簡寫。api
我在圖上分了四個步驟,下面是四步的講解:
第一步:用戶訪問第三方網站,好比:就是你須要使用QQ進行登陸的網站;
第二步:你點擊QQ登陸後,第三方網站將會鏈接並進行請求,好比:你點擊登陸後,第三方網站會跳轉到QQ平臺,提示你進行登陸;
第三步:你要進行受權第三方網站對你的信息訪問的一個權限,好比:當你QQ登陸成功後,QQ會提示你,是否受權第三方Web訪問你的用戶基本信息或其餘的資源信息,這時你點擊受權便可;
第四步:受權後,第三方Web便可訪問你剛纔受權的資源信息,好比:你的QQ基本信息-頭像、暱稱、性別等。安全
第一步:首先直接跳轉至用戶受權地址,即圖示 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了。