2013-02-07 81 views
1

我一直在爲此工作custom timer我爲每個用戶的login session創建。到目前爲止,我無法爲每個登錄會話創建個人timers如何爲個人用戶創建登錄會話計時器

場景:

User1登錄時,timer will start counting。當User2登錄時,Use1的計時器將重置該值與User2的計時器相同。 看來他們有one timer(不是個人)。

這是我想要發生的事情。

  • 當USER1登錄時,他的計時器將開始計數。
  • 如果計時器達到900秒(15分鐘),它會彈出一些模式框,告訴他的會話超時。
  • 的模式將顯示計數倒計數後下來至少30秒
  • ,用戶將被註銷自動
  • 每個用戶都必須有自己的計時器

我已經做了所有的這些除了最後一個項目Every user must have their own timers

下面是創建一個計時器我的代碼:

public class SessionTimer 
{ 
    private static Timer timer; 

    public static void StartTimer() 
    { 
     timer = new Timer(); 
     timer.Interval = (double)Utility.ActivityTimerInterval(); 
     timer.Elapsed += (s, e) => MonitorElapsedTime(); 

     timer.Start(); 
    } 

    public static void ResetTimer() 
    { 
     TimeCount = 0; 
     timer.Stop(); 
     timer.Start(); 
    } 

    public static int TimeCount { get; set; } 

    public static string ConnectionID { get; set; } 

    private static void MonitorElapsedTime() 
    { 
     if (TimeCount >= Utility.TimerValue()) 
     { 
      timer.Stop(); 
      Hubs.Notifier.SessionTimeOut(TimeCount); 
     } 
     else 
     { 
      Hubs.Notifier.SendElapsedTime(TimeCount); 
     } 

     TimeCount++; 
    } 
} 

成功登錄後,我要打電話定時器開始

[HttpPost] 
public ActionResult SignIn(LoginCredentials info) 
{ 
    // Success full login 

    SessionTimer.StartTimer(); 

} 

這裏是服務器的signalr代碼:

public class SessionTimerHub : Hub 
{ 
    public void SendTimeOutNotice(int time) 
    { 
     Clients.Client(Context.ConnectionId).alertClient(time); 
    } 

    public void CheckElapsedTime(int time) 
    { 
     Clients.Client(Context.ConnectionId).sendElapsedTime(time); 
    } 

    public void UpdateConnectionID(string id) 
    { 
     SessionTimer.ConnectionID = id; 
    } 
} 

public class Notifier 
{ 
    public static void SessionTimeOut(int time) 
    { 
     var context = GlobalHost.ConnectionManager.GetHubContext<SessionTimerHub>(); 
     context.Clients.Client(SessionTimer.ConnectionID).alertClient(time); 
    } 

    public static void SendElapsedTime(int time) 
    { 
     var context = GlobalHost.ConnectionManager.GetHubContext<SessionTimerHub>(); 
     context.Clients.Client(SessionTimer.ConnectionID).sendElapsedTime(time); 
    } 
} 

而jQuery代碼:

$(function() { 

     /////////////////////////////////////////////////// SESSION TIMER 
     var timer = $.connection.sessionTimerHub, $modaltimer = $('#session_timer_elapsed'), tt = null; 

     timer.client.alertClient = function (time) { 
      var $count = $modaltimer.find('.timer'), wait = 180; 

      $count.text(wait); 
      $modaltimer.modal('show'); 

      tt = setInterval(function() { 
       $count.text(wait--); 

       if (wait < 0) { 
        $.post('@Url.Action("Logout", "Auth")', function() { window.location.reload(); }); 
        window.clearInterval(tt); 
       } 
      }, 1000); 
     }; 

     timer.client.sendElapsedTime = function (time) { 
      console.log(time); 
     }; 

     $.connection.hub.start().done(function() { 
      timer.server.updateConnectionID($.connection.hub.id); 
     }); 

     $modaltimer.on('click', '.still_here', function() { 
      $.post('@Url.Action("ResetTimer", "Auth")'); 
      $modaltimer.modal('hide'); 
      window.clearInterval(tt); 
     }).on('click', '.log_out', function() { 
      $.post('@Url.Action("Logout", "Auth")', function() { window.location.reload(); }); 
      $modaltimer.modal('hide'); 
     }); 

}); 

正如你可以看到我這樣做:

timer.server.updateConnectionID($.connection.hub.id); 

通過連接ID,因爲我不能得到的ID內public class Notifier

我失敗的解決方案

我試圖把SessionTimersession使用dynamicExpandoObject
如:

public static dynamic Data 
{ 
    get 
    { 
     #region FAILSAFE 
     if (HttpContext.Current.Session[datakey] == null) 
     { 
      HttpContext.Current.Session[datakey] = new ExpandoObject(); 
     } 
     #endregion 

     return (ExpandoObject)HttpContext.Current.Session[datakey]; 
    } 
} 

它成功地分離了定時器。但是經過我的expandoobject可變
e.g連接ID時:

public void UpdateConnectionID(string id) 
{ 
    MyExpandoObject.MySessionTimer.ConnectionID = id; 
} 

它拋出空引用異常。看起來我的expandoObject在傳遞來自SignalR的數據時變得空(只是我的想法),但我不確定。

請幫助我使用這些個人計時器,並在特定用戶的計時器已過時發送消息給特定用戶。

請注意
我想在服務器端創建計時器。

重置從服務器

定時器,定時器必須能夠在服務器上重新設置。在這種情況下,我把當用戶通過[BasecampAuthorize]這意味着他做了一個活動上的每個AcrionReseult

例如爲:

[HttpPost] 
[BasecampAuthorize] 
public ActionResult LoadEmailType() 
{ 
    return Json(Enum.GetNames(typeof(EmailType)).ToList()); 
} 

自定義屬性。
裏面[BasecampAuthorize]

public class BasecampAuthorizeAttribute : AuthorizeAttribute 
{ 
    string url { get; set; } 

    public BasecampAuthorizeAttribute() 
    { 
     if (string.IsNullOrEmpty(url)) 
     { 
      url = "~/SomeUrl"; 
     } 
    } 

    public BasecampAuthorizeAttribute(string URL) 
    { 
     url = URL; 
    } 

    public override void OnAuthorization(AuthorizationContext filterContext) 
    { 
     if (!filterContext.HttpContext.User.Identity.IsAuthenticated) 
     { 
      filterContext.HttpContext.Response.Redirect(url); 
     } 
     else 
     { 
      // MUST RESET SESSION TIMER HERE 
     } 

     base.OnAuthorization(filterContext); 
    } 
} 

@ halter73 - 我怎麼能在這裏所說的復位定時器?

+0

請給一些理由否決。我在問一個很難回答的問題。 – fiberOptics

+0

嗯......可能你討厭我的問題。好的,謝謝。 – fiberOptics

+0

我認爲人們把問題投下來的原因是你不用這種方式創建軟件。爲什麼每個客戶在服務器上都需要自己的計時器?爲什麼他們不能從服務器獲得簽名的令牌,而只是在一定的時間內有效,然後讓客戶端的JavaScript實現計時器? – Henrik

回答

4

你的問題是,你只需要一個靜態的定時器變量是在整個應用程序域共享勁兒實例。在ASP.NET中,AppDomain的每個Web應用程序not per user。你可以使用一個靜態變量,但該變量應該是一個集合,爲每個connectionId保存一個唯一的Timer。如果您在負載均衡器後面擴展,或者IIS重新啓動顯然會創建新的AppDomain的應用程序,則這會崩潰。

public class SessionTimer : IDisposable 
{ 
    public static readonly ConcurrentDictionary<string, SessionTimer> Timers; 

    private readonly Timer timer; 

    static SessionTimer() 
    { 
     Timers = new ConcurrentDictionary<string, SessionTimer>(); 
    } 

    private SessionTimer(string connectionID) 
    { 
     ConnectionID = connectionID; 
     timer = new Timer(); 
     timer.Interval = (double)Utility.ActivityTimerInterval(); 
     timer.Elapsed += (s, e) => MonitorElapsedTime(); 

     timer.Start(); 
    } 

    private int TimeCount { get; set; } 

    private string ConnectionID { get; set; } 

    public static void StartTimer(string connectionID) 
    { 
     var newTimer = new SessionTimer(connectionID); 
     if (!Timers.TryAdd(connectionID, newTimer)) 
     { 
      newTimer.Dispose(); 
     } 
    } 

    public static void StopTimer(string connectionID) 
    { 
     SessionTimer oldTimer; 
     if (Timers.TryRemove(connectionID, out oldTimer)) 
     { 
      oldTimer.Dispose(); 
     } 
    } 

    public void ResetTimer() 
    { 
     TimeCount = 0; 
     timer.Stop(); 
     timer.Start(); 
    } 

    public override Dispose() 
    { 
     // Stop might not be necessary since we call Dispose 
     timer.Stop(); 
     timer.Dispose(); 
    } 

    private void MonitorElapsedTime() 
    { 
     if (TimeCount >= Utility.TimerValue()) 
     { 
      StopTimer(ConnectionID); 
      Hubs.Notifier.SessionTimeOut(ConnectionID, TimeCount); 
     } 
     else 
     { 
      Hubs.Notifier.SendElapsedTime(ConnectionID, TimeCount); 
     } 

     TimeCount++; 
    } 
} 

既然你存儲SessionTimer類內部的連接ID,你可以簡單地呼籲在Notifier類的方法時,把它作爲一個參數。

public static class Notifier 
{ 
    private static context = GlobalHost.ConnectionManager.GetHubContext<SessionTimerHub>(); 

    public static void SessionTimeOut(string connectionID, int time) 
    { 
     context.Clients.Client(connectionID).alertClient(time); 
    } 

    public static void SendElapsedTime(string connectionID, int time) 
    { 
     context.Clients.Client(connectionID).sendElapsedTime(time); 
    } 
} 

你不需要SendTimeOutNoticeCheckElapsedTime因爲你在呼喚你Notifier類客戶端的方法。 UpdateConnectionID可以被OnConnected替代。

public class SessionTimerHub : Hub 
{ 
    public override Task OnConnected() 
    { 
     SessionTimer.StartTimer(Context.ConnectionId); 
     return base.OnConnected(); 
    } 

    public override Task OnDisconnected() 
    { 
     SessionTimer.StopTimer(Context.ConnectionId); 
     return base.OnDisconnected(); 
    } 

    public void ResetTimer() 
    { 
     SessionTimer.Timers[Context.ConnectionId].ResetTimer(); 
    } 
} 

你應該創建SessionTimers內部集線器,所以你可以將它與連接ID相關聯。您可以像OnConnected這樣做,但是這意味着您只有在登錄後才能啓動SignalR連接,並且您確實想要爲該連接啓動SessionTimer。它也有助於在集線器上有ResetTimer,以便您擁有客戶端的連接ID。或者,您可以從$.connection.hub.id獲取客戶端上的連接標識並將其發佈。

$.connection.hub.start().done(function() { 
    $modaltimer.on('click', '.still_here', function() { 
     timer.server.resetTimer(); 
     $.post('@Url.Action("ResetTimer", "Auth")'); 
     $modaltimer.modal('hide'); 
     window.clearInterval(tt); 
    }); 
}); 

編輯:

如果由於某種原因SessionTimerHub.ResetTimer拋出一個KeyNotFoundException(這不應該發生,如果你調用timer.server.resetTimer$.connection.hub.start().done火災),你可以做到以下幾點:

public void ResetTimer() 
{ 
    SessionTimer timer; 
    if (SessionTimer.Timers.TryGetValue(Context.ConnectionId, out timer)) 
    { 
     timer.ResetTimer(); 
    } 
    else 
    { 
     SessionTimer.StartTimer(Context.ConnectionId); 
    } 
} 

如果由於某些原因IIS正在重新啓動您的應用程序,您可能需要將其添加到SessionTimerHub.OnReconnected中,因爲客戶端將重新連接,但您的靜態SessionTimer.Timers將被重置,並且你所有的SessionTimers都將消失。

public override Task OnReconnected() 
{ 
    if (!SessionTimer.Timers.ContainsKey(Context.ConnectionId)) 
    { 
     SessionTimer.StartTimer(Context.ConnectionId); 
    } 
    return base.OnReconnected(); 
} 

你不曾在C#中調用SessionTimerHub.ResetTimer()對不對?

+0

來自天堂的祝福!謝謝你的回答,我已經嘗試過了,它的工作原理!但我忘了包括重置計時器必須的方法,'1)從點擊**是我在這裏**從客戶端,'和'2)從服務器.'請參閱我的編輯。謝謝! '它引發錯誤'KeyNotFoundException'; – fiberOptics

+0

那裏調用'SessionTimer.Timers [Context.ConnectionId] .ResetTimer()時是一個問題。當我檢查'SessionTimer.Timers'計數是0.爲什麼會發生? – fiberOptics

+0

檢索SessionTimer.Timers [Context.ConnectionId]應該總是工作,如果它被調用在'$ .connection.hub.start()調用'timer.server.resetTimer'。done'。您可以執行'Timers.TryGetValue' http://msdn.microsoft.com/en-us/library/dd267270.aspx,如果它不存在,則啓動一個新的SessionTimer。 – halter73

-4

在母版頁:

public partial class MasterPage : System.Web.UI.MasterPage 
{ 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     if (Session["LoginID"] != null) 
      Label1.Text="Welcome :: " + Session["LoginID"].ToString(); 
     else 
      Response.Redirect("Login.aspx"); 

    } 
    protected void lnkLogout_Click(object sender, EventArgs e) 
    { 
     Session["LoginID"] = null; 
     Response.Redirect("Login.aspx"); 

    } 
} 
在CS頁面

protected void Login_Click(object sender, EventArgs e) 
    { 
     string conString = "Provider=Microsoft.JET.OLEDB.4.0; data source=" + Server.MapPath (string.Empty) + @"\Database\Northwind.mdb"; 
     string sqlString = "SELECT * FROM CUSTOMERS where CustomerID='" + TextBox1.Text + "' and City='" + TextBox2.Text + "'"; 
     OleDbConnection conn = new OleDbConnection(conString); 
     DataSet ds = new DataSet(); 
     OleDbDataAdapter adapter = new OleDbDataAdapter(sqlString, conn); 
     adapter.Fill(ds); 
     if (ds != null) 
     { 
      if (ds.Tables[0].Rows.Count > 0) 
      { 
       Session["LoginID"] = ds.Tables[0].Rows[0]["CustomerID"].ToString(); 
       Response.Redirect("Welcome.aspx"); 

      } 
      else 
       Label1.Text = "Enter correct id/city"; 
     } 


    } 
} 
+0

抱歉,但我認爲這不是我要找的。 – fiberOptics

+1

請修復您的代碼。目前它不可讀。 – Impulss

0

已經有一個世界的計時器:用戶的時鐘。讓用戶自己的時間在登錄時倒計時:在JavaScript cookie中保存他的個人日誌。

假設我們使用RSA密鑰驗證用戶(openssl genrsa 2048)。

的convesation現在去:

> GET /login 

< 200 OK 
challenge: mie4NaNgfcqwkhYtNiy4oF 

<form action='/login'> 
    <input type='text' name='user-public-key' /> 
    <input type='text' name='rsa-signed-challenge' /> 
</form> 

> POST /login 
-----BEGIN PUBLIC KEY----- 
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA24PnkIZYg/k6lLbNZl5X 
IxNl8KEsJTUX7h9B2P+o5LjB6e1OozVwsPFwXjCJP3WN8KwBQhvpxH4ZCK9H0LyT 
+NXBPCsydBgY2VfqKK3wQONRKUaEQkSlV/gA0ciWa/jXD9FDbc3onrlqNTmtjGiM 
OkXzSJDPz67tEDx+sZQ/+zcEO9tVPSioq6tZwMHx3EfBratA9W148OZRLOS1AFmc 
RSSJzsgj/MmOTxrGjfNE2dKMvul4usjWf8Of+GEpEqW6+SrKZ3ivhP/jx+q1v8Bp 
pbhDYag6I+YTwEu4feXJEgM4z83e05DJvh3hUDgzv7KDMqCp/h3m8f3TolcgvNox 
fQIDAQAB 
-----END PUBLIC KEY----- 

rsa-signed-challenge: 
IyGoX2aqQOH/tBRxxxGPIWGmbo2r6KfEmcDUdDvt7nNaN0GwqXm6MZaJ6eQvjkCR 
AVnVRpJNGQDWCaLqzyBLVrysTlnC0dHkJD/vJg3jv74UqZGOqeKSW06HIhzz79UY 
RghkdjadDpA8Jzs8NSYBzFopExfzSz+K1sOOwVXWa9nywhGqEj7XXoJO1I0j+o63 
Wt94xEa30gmW1oVWIvjWLnBewH4H9ZzXv8PeGTdLdp2v9c9a3nsd7PsYi2yHul+S 
CfAlFo/hITfEqucUX5zgyJyU0+SAVRod+vRlSaimMW2CQq8K8kQSbADaQpET4pa1 
9eVnG99rz2UHw9b6UG0nBQ== 

< 301 Redirect /dashboard 
< Set-Cookie: Token= 
iPtyfAxAcenFog1kn/h5VrdkBj0wxjeZBnB4JfXLcOWlh+G6/GdndgT7VTg3rSyq 
uNFfbgnKNQtiGBjJ45cUHDai44ILK0g6DXPcicusEhs30xJhh8CT4P2FfK/juTtz 
d0nj9ypncFOsUPAzJdirgdxO9oMquw0DW2b/iG1O/Dn2fU1/lDrmFpKKIMnPZ10g 
cD6gY7Yhqs+2OcyfuiuIBYf2tAq8LYtKSm69j0AlgEiFNNmPl12Wr1R7YhxJZ1hi 
smDjNTom5tDfxi3LDfwFtsHKn61OCbfuI3PhlPPqYTUd6omL1Efbr29l4jj+9cgF 
0NnaX1L6LUUd6RaVmCw30w== 


> GET /dashboard 
> Cookie: Token= 
iPtyfAxAcenFog1kn/h5VrdkBj0wxjeZBnB4JfXLcOWlh+G6/GdndgT7VTg3rSyq 
uNFfbgnKNQtiGBjJ45cUHDai44ILK0g6DXPcicusEhs30xJhh8CT4P2FfK/juTtz 
d0nj9ypncFOsUPAzJdirgdxO9oMquw0DW2b/iG1O/Dn2fU1/lDrmFpKKIMnPZ10g 
cD6gY7Yhqs+2OcyfuiuIBYf2tAq8LYtKSm69j0AlgEiFNNmPl12Wr1R7YhxJZ1hi 
smDjNTom5tDfxi3LDfwFtsHKn61OCbfuI3PhlPPqYTUd6omL1Efbr29l4jj+9cgF 
0NnaX1L6LUUd6RaVmCw30w== 

< 200 OK 
<html> 
<head> 
    <script> 
    jQuery.fn.startCountDown = function(el, opts) { 
     opts = $.extend({ minutes : 20 }, opts); 
     var start = new Time(); 
     var updater = function() { el.text("Seconds left: " + (opts.minutes * 60 - ((new Time()) - start))); } 
     setTimeout(1000, updater); 
    } 
    $(function() { 
     $("#timer").startCountDown({ minutes: 30 }); 
    }) 
    </script> 
</head> 
<body><p id="timer"></p></body> 
</html> 

這裏的關鍵是,你不能信任客戶端提供計數減少的一個理智的價值,所以上述方案加密登錄和使用的時間作爲令牌。

這是從客戶的角度。

$ openssl genrsa 2048 >client.key 
-----BEGIN RSA PRIVATE KEY----- 
MIIEpQIBAAKCAQEA24PnkIZYg/k6lLbNZl5XIxNl8KEsJTUX7h9B2P+o5LjB6e1O 
ozVwsPFwXjCJP3WN8KwBQhvpxH4ZCK9H0LyT+NXBPCsydBgY2VfqKK3wQONRKUaE 
QkSlV/gA0ciWa/jXD9FDbc3onrlqNTmtjGiMOkXzSJDPz67tEDx+sZQ/+zcEO9tV 
PSioq6tZwMHx3EfBratA9W148OZRLOS1AFmcRSSJzsgj/MmOTxrGjfNE2dKMvul4 
usjWf8Of+GEpEqW6+SrKZ3ivhP/jx+q1v8BppbhDYag6I+YTwEu4feXJEgM4z83e 
05DJvh3hUDgzv7KDMqCp/h3m8f3TolcgvNoxfQIDAQABAoIBAQCg8VrsObPYPvjW 
ZBjAf1a/3s8U1/Z36S98ZOpwYTHBUDzMeDL5sorHEJ3kUQ2vu06wMExT3gdNC27r 
USgEQN70yDP/G2TIfYpqf+ysmqrVyFSPQKZjt9TKZIilRr4St8VmUXVwolF1Xlgi 
YgF+OoDlkLfIcnQKvyQMjW4OYLVwRw+bCKAq/T45kki+X41VK4Ubsnjddy+yT++3 
GKMPqezVmZHGuhyVtR+dB9vQB3zWZocQRrqDDoQviDB7+scQD2XeWz53SUScBdwm 
TzW5YaYclbttVWib0okCSxnhF3yah8cqvQHgqalrACnhaQx9oLcqyrg6KLCI/Lnn 
yOZLvKZ5AoGBAP46Y8waGAYgPtgI/7Rni4NslnANGh6psWKaELftPLThxiuCoHad 
rMpSojqP8FbKgqILDUOwczPIy/+jWK6J8EJPv4za2dlOcGnnfzD3Ko6LN2Jq3reC 
N0Ywi3esTaesHp/SDOB39xW3XAAkdsejffy+LHsnrpVKYKlVm43Jhy6nAoGBAN0L 
k+0m9RgwOxWiiAJK3XSBgdHK0e9BnVMKFVPiS2Q1wrnOUDb1CansAAyYSVZYsJZD 
eh5VocYPGPTydl/muywlPceGgW2O1CO/LZPj1cKQANHx0+6F9itmk8leaTR4rTuf 
2G67sdvlYCyKPoIvVg3WJQnj3dsqo4Ldt/5KkSc7AoGBAMDbIqHOmbLr+0B/cxs0 
AY3tbiIKjmn8aOhX357nhUnijCatrXTOICpLjW3Hi5cLgRXUNHfI/1ulU7vV+oxN 
b8meHb2IuAI1kumEB+TpW4tO6PDsCZBEZBIG+YYLW816sLCk88fEudfrhQtGniTM 
TeLRkYTLkZEHH1TV8G8bFkW5AoGAXf9XZ2jCnwebiIa2KatmYu3To8AI6CJR4YcP 
LL21a6bE6LiIOeaXtm+KUdDMlvBeH3gQTSgDBDNVXIxitENs4sfvbpKPJWSwZ4cb 
vaEMPJF6F80rX2oOFcSoIeCJAmwy1oERy3z7lFQFQsuC619vy7B9zafdpx6Jq9PX 
M0bIVRMCgYEAy9LvPbyXMWYmOy9svYRy4iAL9sCRNmzZgvC5B5b3lN55EWoE8ipw 
g4qNBv3NaCJ/lTFezRQZVRfFfQOpNGDvJBLmTEaSR3OuV8hRw7zttC3/MazDqwTy 
qZeg526uklXN7IvkFfiHlYZeed1u4wc7SXSi76RIE0w5lDBIb+CPPM4= 
-----END RSA PRIVATE KEY----- 

$ openssl rsa -in client.key -pubout >client.key.pub 
-----BEGIN PUBLIC KEY----- 
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA24PnkIZYg/k6lLbNZl5X 
IxNl8KEsJTUX7h9B2P+o5LjB6e1OozVwsPFwXjCJP3WN8KwBQhvpxH4ZCK9H0LyT 
+NXBPCsydBgY2VfqKK3wQONRKUaEQkSlV/gA0ciWa/jXD9FDbc3onrlqNTmtjGiM 
OkXzSJDPz67tEDx+sZQ/+zcEO9tVPSioq6tZwMHx3EfBratA9W148OZRLOS1AFmc 
RSSJzsgj/MmOTxrGjfNE2dKMvul4usjWf8Of+GEpEqW6+SrKZ3ivhP/jx+q1v8Bp 
pbhDYag6I+YTwEu4feXJEgM4z83e05DJvh3hUDgzv7KDMqCp/h3m8f3TolcgvNox 
fQIDAQAB 
-----END PUBLIC KEY----- 

這是我們從服務器獲取的挑戰(隨機垃圾)

$ echo "mie4NaNgfcqwkhYtNiy4oF" >to-sign 
$ openssl dgst -sha1 -sign client.key -out to-sign.sha1 to-sign 

(可選:確保客戶的簽名作品)

$ openssl dgst -sha1 -verify client.key.pub -signature to-sign.sha1 to-sign 

現在你可以編碼客戶端以可複製的方式簽名:

$ cat to-sign.sha1 | openssl base64 -e 
g8nbi3mrcZ8afEpf4iRG6TQFDJtxw48AJ0QTKOdTKh2khxbQdPQIxAFWU++xsJRd 
m0wnKRc1SpEYxhLeMKYjyhMTDce/KUBM/5i1Hoh9RPi9+G/cxNoXJiVKaxIF+rDf 
NYk7mQD9ofdYgBCAbu2hi6jR5t2BY6emd7z/F53E8edVFtzqlHYjVLHNNYiNlXqD 
WHl9OLV2b+yHY/mAkgUBYoVjyBvFnHFcRxTrZMC9A8K3jfU/bEOLgxEmq3UgmvWC 
2M7fwpOBAUN7q9yoIR/kOGNPqePghhHTuyeFtbC33PmD8qgbgVUQby8jpVQ7T+5Q 
kjEP2sbnETHlkjS6TXSKHg== 

現在讓我們簽署的認證令牌,所以我們移動到服務器...

$ openssl genrsa 2048 >server.key 
-----BEGIN RSA PRIVATE KEY----- 
MIIEpAIBAAKCAQEAoD80ZhPHm1x62wAESbEdHmzCdYCwC3VwkOwDMr4fD9Qqmw6D 
Zu2oMSAJ8Kw1Q4oRJd3sZkHu7ZnCwHTe3P83uBKrCfDDFiu/aB1mJQJDAZzPwh5r 
W8/2FAHmq/iw/f3U3IOaPuE1w7eoEaqFuNnmfb0EEBhsi7zhbjKpKowUXObPz1W5 
mIJvpWqlyygHG6+JJVMs1jTdwzzQzcyHZDgEu/fODHgW5ErBQS7fKOOvZZIxEuLg 
i7x5xB/mMYpWdIO0BI/xcu3SdmmNE/Ix8MoAZXXTK9u8Uu+2jnO69pFWtBGPIa2l 
AGKNQ1jlUgvECglo356OOpKx9rb9Fd9WY4SIxwIDAQABAoIBABIiFNPYOSYjeON/ 
RPzxxdHDjN2vCjzBtVMw4cvEJ8+quoeBRO1Ix1eHwJgzZHOYFAis7CtGGrtYQul0 
UCPB3ZQ+yIv/apP/r1EgwoY9k0eDbx8QQiXJipcJAAlFwwF6z7OEUNf8tBDJn4Mg 
QLGCNsrTsLoBiYbmgLvvj6T45PT+G3ztaETv7iiiUIMX5R/7thK/+odiUeqyIbHH 
m0673m0nYdZvGe7ujZarbh1h2x4Srs+OiMaPXH1ehw/nTvYAoEgGvz8eGVFCUrfa 
87rizYMLYk8zs/TAz4CDtAk9PtLVMS6NZdKCYe4zvLBdjGjwx7gQJFpjXJCRQwA2 
JGE8U8ECgYEAzn4I5yHc+ApzJDJyRmeR70MMWk0KpzIi+8PhwKUNpdP3DyKGOTAs 
Z3g3su1/C5tcq2GIK/hprvDxdtg7wu7RSZdhz1W3Ee584JTqzqAG464bmCqd1aPi 
sp7DVOeSrb5EZDtrZ9UpW79R2skRhU3qLAay0bl/cvKauBukCr0gUUsCgYEAxqq+ 
slkXI1tvCzaoxAWNyf0hooGKjEeAsCyrFYJwVk9cveJ0wMZUC7pLPH9UVEIjZzzo 
Fm+xr5kVbXhLBn9cCXjP/OgBtuM1KqA/mcsmysVn2okuU8BIy43RYXgq1+eUI92/ 
MDFKtuFzMikSqI5gY3sIB0GRfL19FAvdy4iKtPUCgYEApUiJA8k9QGXM6Epg4i4A 
yA1ZE+bbAh3FltSiHTuAgx35genWmmwO/vthSh2ENdwz/xJglyGOJnPCM6i9nTjf 
2RINPpKTqQzGdFV+5cl9+jzg5ZonIFzAFs2x+IIsDFpiEADn5gLfygqIEKIlHhjR 
uk/aTrk2ZOIAKiIl2lqsRaUCgYA3K8O5k7QxRXsZChzkEwbFSV7F2mO3gUPjqQP5 
/TdlQLToprL1th4xA5NRQasRmyxpxyhM0sftk/23YOi07TmKB9r6yRNwzrg9FjOT 
ai9jsF6e+em7qHKO1NuIze5X9x/UtggaQhYVo5ZyH6Xm2WM7PTeFjFfy5EyP/Juj 
ok+i4QKBgQCf6mndYOkBCmzyMv2gASr8nj7Fh0oTxfaFRrs9k/DnUTOSUgrHrmO4 
eCAk/D5FdPjcmF1np8wasVt38sw5nxUmbYonoV/2H+xmvKrRqtuflGRQx98P/+Qd 
6vIF/n3NM66oZG9zgeYdEzxAbLXptCO60arJ4Ekrod/J+EpGSQb+bg== 

下面是設置在服務器已經運行:

$ openssl rsa -in server.key -pubout >server.key.pub 
-----BEGIN PUBLIC KEY----- 
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoD80ZhPHm1x62wAESbEd 
HmzCdYCwC3VwkOwDMr4fD9Qqmw6DZu2oMSAJ8Kw1Q4oRJd3sZkHu7ZnCwHTe3P83 
uBKrCfDDFiu/aB1mJQJDAZzPwh5rW8/2FAHmq/iw/f3U3IOaPuE1w7eoEaqFuNnm 
fb0EEBhsi7zhbjKpKowUXObPz1W5mIJvpWqlyygHG6+JJVMs1jTdwzzQzcyHZDgE 
u/fODHgW5ErBQS7fKOOvZZIxEuLgi7x5xB/mMYpWdIO0BI/xcu3SdmmNE/Ix8MoA 
ZXXTK9u8Uu+2jnO69pFWtBGPIa2lAGKNQ1jlUgvECglo356OOpKx9rb9Fd9WY4SI 
xwIDAQAB 
-----END PUBLIC KEY----- 

現在服務器有私鑰和公鑰,讓我們創建令牌爲 簽名並用於身份驗證。

$ echo "2013-02-09T16:33:44+0000" >auth.token.plain 

因爲加密的文字是如此的渺小,我們不會遇到與關鍵 長度在服務器上的問題,所以我們可以使用密鑰原樣,而不是做 對稱加密。

$ openssl rsautl -encrypt -inkey server.key.pub -pubin -in auth.token.plain -out auth.token.cipher 

這是我們給客戶的。每次我們收到此令牌時,我們都可以驗證我們簽署的 。如果您有服務器場,請使用相同的密鑰進行簽名。

$ cat auth.token.cipher | openssl base64 -e 
iPtyfAxAcenFog1kn/h5VrdkBj0wxjeZBnB4JfXLcOWlh+G6/GdndgT7VTg3rSyq 
uNFfbgnKNQtiGBjJ45cUHDai44ILK0g6DXPcicusEhs30xJhh8CT4P2FfK/juTtz 
d0nj9ypncFOsUPAzJdirgdxO9oMquw0DW2b/iG1O/Dn2fU1/lDrmFpKKIMnPZ10g 
cD6gY7Yhqs+2OcyfuiuIBYf2tAq8LYtKSm69j0AlgEiFNNmPl12Wr1R7YhxJZ1hi 
smDjNTom5tDfxi3LDfwFtsHKn61OCbfuI3PhlPPqYTUd6omL1Efbr29l4jj+9cgF 
0NnaX1L6LUUd6RaVmCw30w== 

服務器可以再次驗證令牌。解密密碼失敗意味着 它已被修改,並且令牌失效。一種生產系統,還應該 驗證簽名(在相同的包絡),以避免損壞的數據解密 成功。

$ openssl rsautl -decrypt -inkey server.key -in auth.token.cipher 
2013-02-09T16:33:44+0000