2

我一直在研究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();

}  

这是服务器上的信号器代码:

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,因为我无法得到里面的IDpublic class Notifier

我失败的解决方案

我尝试将其SessionTimer放入session使用中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 变量上传递连接 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 - 我如何在这里调用重置计时器?

4

3 回答 3

6

您的问题是您只有一个静态计时器变量,它是整个 AppDomain 共享的单一实例。在 ASP.NET 中,AppDomain 是每个 Web 应用程序而不是每个用户。您可以使用静态变量,但该变量应该是为每个 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++;
    }
}

由于您将连接 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);
    }
}

您不需要SendTimeOutNoticeorCheckElapsedTime因为您在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抛出 a 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 将被重置,并且您的所有 SessionTimer 都将消失。

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

你从来没有SessionTimerHub.ResetTimer()在 C# 中调用过,对吧?

于 2013-02-08T04:56:27.220 回答
0

世界上已经有一个计时器:用户的时钟。让用户在登录时倒计时:将他的个人登录时间保存在 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
于 2013-02-09T16:13:38.697 回答
-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";
        }


    }
}
于 2013-02-07T06:27:20.527 回答