一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - ASP.NET教程 - .net 單點登錄的設(shè)計與實踐

.net 單點登錄的設(shè)計與實踐

2020-03-31 18:27漫漫摸索 ASP.NET教程

本篇文章主要介紹了解析.net 單點登錄實踐,具有一定的參考價值,有需要的可以了解一下。

前言

最近輪到我在小組晨會來分享知識點,突然想到單點登錄,準(zhǔn)備來分享下如何實現(xiàn)單點登錄,所以有了下文。實現(xiàn)方案以及代碼可能寫得不是很嚴(yán)謹(jǐn),有漏洞的地方或者錯誤的地方歡迎大家指正。  

剛開始頭腦中沒有思路,直接在博客園里面看看別人是如何來實現(xiàn)的,看了幾篇文章發(fā)現(xiàn),發(fā)現(xiàn)解決方案有點問題,或者說不算實現(xiàn)了單點登錄

名稱定義

為了方便說明先說明幾個文中出現(xiàn)的名詞的含義:

P站:統(tǒng)一登錄授權(quán)驗證中心,demo中 域名是www.passport.com:801

A站:處于不同域名下的測試網(wǎng)站,demo中 域名是www.a.com:802

B站:處于不同域名下的測試網(wǎng)站,demo中 域名是www.b.com:803

Token:用戶訪問P站的秘鑰

Ticket:用來保存用戶信息的加密字符串

單點登錄

訪問A站需要登陸的就跳轉(zhuǎn)P站中進(jìn)行登陸,P站登陸之后跳轉(zhuǎn)回至A站,用戶再次訪問B站需要登陸的頁面,用戶不需要進(jìn)行登陸操作就可以正常訪問。

實現(xiàn)思路

未登錄用戶訪問A站,首先會重定向跳轉(zhuǎn)至P站授權(quán)中心,P站首先通過檢測Cookie來判斷當(dāng)前不是處于登陸狀態(tài),就跳轉(zhuǎn)至登陸頁面進(jìn)行登陸操作,登陸成功之后把用戶信息加密ticket附在A的請求地址上返回,A站通過解密ticket來獲取用戶信息,解密成功并存進(jìn)Session中(這樣用戶在A中就處于登陸狀態(tài)了),訪問通過;當(dāng)用戶再次訪問B站的時候,對于B站來說,用戶是處于未登錄狀態(tài),則同樣會重定向跳轉(zhuǎn)至P站授權(quán)中心,P站檢測Cookie,判斷當(dāng)前用戶處于登陸狀態(tài),就把當(dāng)前用戶信息加密成ticket附在B的請求地址上返回,后面的操作就和A站處理一樣;這樣都登陸之后再次訪問A或者B,A和B中Session中都存儲了用戶信息,就不會再次請求P站了。

簡單關(guān)系圖
.net 單點登錄的設(shè)計與實踐

泳道流程圖.net 單點登錄的設(shè)計與實踐

主要邏輯說明

A站主要邏輯

用戶首先訪問A站,A站中會生成Token,并存入Cache中。Token是A訪問P的鑰匙,P在回調(diào)給A的時候需要攜帶這個Token。A請求P,P驗證Token,P回調(diào)A,A檢測Token是否是發(fā)送出去的Token,驗證之后Token即失效,防止Token被再次使用。

Token的生成是通過取時間戳的不同字段進(jìn)行MD5加密生成,當(dāng)然這里可以再加個鹽進(jìn)行防偽。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/// <summary>
    /// 生成秘鑰
    /// </summary>
    /// <param name="timestamp"></param>
    /// <returns></returns>
    public static string CreateToken(DateTime timestamp)
    {
      StringBuilder securityKey = new StringBuilder(MD5Encypt(timestamp.ToString("yyyy")));
      securityKey.Append(MD5Encypt(timestamp.ToString("MM")));
      securityKey.Append(MD5Encypt(timestamp.ToString("dd")));
      securityKey.Append(MD5Encypt(timestamp.ToString("HH")));
      securityKey.Append(MD5Encypt(timestamp.ToString("mm")));
      securityKey.Append(MD5Encypt(timestamp.ToString("ss")));
      return MD5Encypt(securityKey.ToString());
    }

P回調(diào)A的時候進(jìn)行,A中對Token進(jìn)行校驗,校驗不成功則請求P站統(tǒng)一授權(quán)驗證。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/// <summary>
  /// 授權(quán)枚舉
  /// </summary>
  public enum AuthCodeEnum
  {
    Public = 1,
    Login = 2
  }
 
  /// <summary>
  /// 授權(quán)過濾器
  /// </summary>
  public class AuthAttribute : ActionFilterAttribute
  {
    /// <summary>
    /// 權(quán)限代碼
    /// </summary>
    public AuthCodeEnum Code { get; set; }
 
    /// <summary>
    /// 驗證權(quán)限
    /// </summary>
    /// <param name="filterContext"></param>
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
      var request = filterContext.HttpContext.Request;
      var session = filterContext.HttpContext.Session;
      //如果存在身份信息
      if (Common.CurrentUser == null)
      {
        if (Code == AuthCodeEnum.Public)
        {
          return;
        }
        string reqToken = request["Token"];
        string ticket = request["Ticket"];
        Cache cache = HttpContext.Current.Cache;
        //沒有獲取到Token或者Token驗證不通過或者沒有取到從P回調(diào)的ticket 都進(jìn)行再次請求P
        TokenModel tokenModel= cache.Get(ConstantHelper.TOKEN_KEY)==null?null:(TokenModel)cache.Get(ConstantHelper.TOKEN_KEY);
        if (string.IsNullOrEmpty(reqToken) || tokenModel == null || tokenModel.Token!= reqToken ||
          string.IsNullOrEmpty(ticket))
        {
          DateTime timestamp = DateTime.Now;
          string returnUrl = request.Url.AbsoluteUri;
          tokenModel = new TokenModel
          {
            TimeStamp = timestamp,
            Token = AuthernUtil.CreateToken(timestamp)
          };
          //Token加入緩存中,設(shè)計過期時間為20分鐘
          cache.Add(ConstantHelper.TOKEN_KEY, tokenModel, null, DateTime.Now.AddMinutes(20),Cache.NoSlidingExpiration,CacheItemPriority.Default, null);
          filterContext.Result = new ContentResult
          {
            Content = GetAuthernScript(AuthernUtil.GetAutherUrl(tokenModel.Token, timestamp), returnUrl)
          };
          return;
        }
        LoginService service = new LoginService();
        var userinfo = service.GetUserInfo(ticket);
        session[ConstantHelper.USER_SESSION_KEY] = userinfo;
        //驗證通過,cache中去掉Token,保證每個token只能使用一次
        cache.Remove(ConstantHelper.TOKEN_KEY);
      }
    }
 
    /// <summary>
    /// 生成跳轉(zhuǎn)腳本
    /// </summary>
    /// <param name="authernUrl">統(tǒng)一授權(quán)地址</param>
    /// <param name="returnUrl">回調(diào)地址</param>
    /// <returns></returns>
    private string GetAuthernScript(string authernUrl, string returnUrl)
    {
      StringBuilder sbScript = new StringBuilder();
      sbScript.Append("<script type='text/javascript'>");
      sbScript.AppendFormat("window.location.href='{0}&returnUrl=' + encodeURIComponent('{1}');", authernUrl, returnUrl);
      sbScript.Append("</script>");
      return sbScript.ToString();
    }
  }

代碼說明:這里為了方便設(shè)置Token的過期時間,所以使用Cache來存取Token,設(shè)定Token的失效時間為兩分鐘,當(dāng)驗證成功則從cache中移除Token。

調(diào)取過濾器

?
1
2
3
4
5
[Auth(Code = AuthCodeEnum.Login)]
     public ActionResult Index()
     {
       return View();
    }

P站主要邏輯

P站收到授權(quán)請求,P站首先通過Coookie來判斷是否登陸,未登錄則跳轉(zhuǎn)至登陸頁面進(jìn)行登陸操作。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/// <summary>
    /// 授權(quán)登陸驗證
    /// </summary>
    /// <returns></returns>
    [HttpPost]
    public ActionResult PassportVertify()
    {
      var cookie=Request.Cookies[ConstantHelper.USER_COOKIE_KEY];
      if (cookie == null ||string.IsNullOrEmpty(cookie.ToString()))
      {
        return RedirectToAction("Login", new { ReturnUrl = Request["ReturnUrl"] ,Token= Request["Token"] });
      }
      string userinfo = cookie.ToString();
      var success= passportservice.AuthernVertify(Request["Token"], Convert.ToDateTime(Request["TimeStamp"]));
      if (!success)
      {
        return RedirectToAction("Login", new { ReturnUrl = Request["ReturnUrl"], Token = Request["Token"] });
      }
      return Redirect(passportservice.GetReturnUrl(userinfo, Request["Token"],Request["ReturnUrl"]));
    }

已登陸則驗證Token

?
1
2
3
4
5
6
7
8
9
10
/// <summary>
    /// 驗證令牌
    /// </summary>
    /// <param name="token">令牌</param>
    /// <param name="timestamp">時間戳</param>
    /// <returns></returns>
    public bool AuthernVertify(string token,DateTime timestamp)
    {
      return AuthernUtil.CreateToken(timestamp) == token;
    }

測試說明

1、修改host

127.0.0.1 www.passport.com

127.0.0.1 www.a.com

127.0.0.1 www.b.com

2、部署IIS

P www.passport.com:801

A www.a.com:802

B www.b.com:803

3、測試賬號和webconfig

<add key="PassportCenterUrl" value="http://www.passport.com:801"/>

用戶名:admin  密碼:123

demo

下載地址:源碼下載地址

原文鏈接:http://www.cnblogs.com/minesnil-forfaith/p/6062943.html

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 好大好硬好紧太深了受不了 | 99久久免费看国产精品 | sp啪啪调教打屁股网站 | 国产在线看片网站 | 欧美性野久久久久久久久 | 欧美靠逼视频 | 免费在线观看伦理片 | 1769亚洲资源站365在线 | 激情小视频 | 国产主播福利在线观看 | 视频在线观看入口一二三2021 | 忘忧草秋观看未满十八 | 爱爱小说漫画 | www.青青草原 | 调教人妖 | 99热精品成人免费观看 | 特黄级 | 色哟哟在线播放 | 国产真实偷乱视频在线观看 | 吉川爱美与黑人解禁 | 春宵福利网站在线观看 | 精品无人区乱码1区2区3区在线 | 好男人影视社区www在线观看 | 久久这里只有精品国产精品99 | 久久精品中文闷骚内射 | 国产欧美二区三区 | 无码任你躁久久久久久久 | 日本韩国推理片免费观看网站 | 日本艳鉧动漫1~6完整版在 | 91精品综合久久久久久五月天 | 亚洲天堂激情 | 秋霞一级成人欧美理论 | 久久国产加勒比精品无码 | 沉香如屑西瓜视频免费观看完整版 | 日韩无砖专区2020在线 | 黑人chinese女人 | 日本国产成人精品视频 | 91啦在线播放 | 久久久精品免费视频 | 四虎院影永久在线观看 | 四虎影视e456fcom四虎影视 |