如何为单个用户创建登录会话计时器
本文关键字:登录 会话 计时器 创建 用户 单个 | 更新日期: 2023-09-27 17:58:10
我一直在研究我为每个用户的login session
创建的custom timer
。到目前为止,我无法为每个登录会话进行单独的timers
。
场景:
当User1
登录时,timer will start counting
.当User2
登录时,Use1的计时器将重置该值与User2的计时器相同。似乎他们有one timer
(不是个人(。
这就是我想要发生的事情。
- 当用户 1 登录时,他的计时器将开始计数。
- 如果计时器达到 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();
}
这是服务器上的信号器代码:
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,因为我无法在 public class Notifier
中获取 ID
我失败的解决方案
我尝试使用dynamic
和ExpandoObject
将SessionTimer
放入session
例如:
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];
}
}
它成功地分离了计时器。但是在我的扩展对象变量
上传递连接 id 时例如:
public void UpdateConnectionID(string id)
{
MyExpandoObject.MySessionTimer.ConnectionID = id;
}
它引发空引用异常。从 SignalR 传递数据时,我的 expandoObject 似乎变得为空(只是我的想法(,但我不确定。
请帮助我使用这个单独的计时器,并在计时器过后向特定用户发送消息。
请注意我想在服务器端创建计时器。
从服务器重置计时器
计时器必须能够在服务器上重置。在这种情况下,我将自定义属性放在每个AcrionReseult
例如:
[HttpPost]
[BasecampAuthorize]
public ActionResult LoadEmailType()
{
return Json(Enum.GetNames(typeof(EmailType)).ToList());
}
当用户通过[BasecampAuthorize]
时,这意味着他进行了活动。
内[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 - 如何在此处调用重置计时器?
您的问题是您只有一个静态计时器变量,该变量是在整个 AppDomain 中共享的签名实例。在 ASP.NET 中,AppDomain是每个Web应用程序而不是每个用户。可以使用静态变量,但该变量应是一个集合,其中包含每个 connectionId 的唯一计时器。如果在负载平衡器后面横向扩展或 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++;
}
}
由于将连接 ID 存储在 SessionTimer
类中,因此在调用 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);
}
}
您不需要SendTimeOutNotice
或CheckElapsedTime
,因为您要在 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。或者,可以从客户端上获取连接 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()
吧?
已经有一个世界的计时器:用户的时钟。让用户登录时自己的时间倒计时:将他的个人登录时间保存在javascript cookie中。
假设我们正在使用 RSA 密钥 ( openssl genrsa 2048
( 对用户进行身份验证。
现在的对话是:
> 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
在母版页中:
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";
}
}
}