分享

ASP.NET 实现多站点统一登录

 我的阳光书吧 2012-03-17
现在网络上的身份验证一般都是采用用户名+口令的形式,几乎每到一个提供服务的网站都要求进行验证登录。随着网络身份的增多,这也会造成用户名与口令记忆上的负担,另外多次的输入也存在安全隐患(输多了,被盗的机会也多)。单点登录就是为了解决这些问题而产生的,它指的是在一个地方登录就可以到处通行。 (哇靠,发现自己老了几岁,另起一段,讲点实际的)。

    我们公司有几个网站需要维护,每个站点都具有一个登录口,我们发现这样很不方便,所以第一步就是统一这些登录口。虽然所有的源代码都可以控制,我们可以把所有站点改成一个站点,这样就不存在这个问题了,只是这样不符合要求,所以当时(几前天)只能另想办法。 我们找到了微软的Passport,发现有点麻烦,要申请Web服务(也许并不麻烦,因为没有用过,新技术总让人感觉神秘嘛),就决定不用它,就几点站点,不想劳师动众。后来同事(我的经理)找到了一篇相关的文章,在ASP.NET下,只要在Web.config下配置machineKey节,可以解决这个问题(我是指我们公司的这个问题)。

在.NET Framework SDK文档中,ASP.NET设置架构篇中,可以找到machineKey的相关内容:

对密钥进行配置,以便将其用于对 Forms 身份验证 Cookie 数据和视图状态数据进行加密和解密,并将其用于对进程外会话状态标识进行验证。该节可在计算机、站点和应用程序级别声明,但不在子目录级别声明。

<configuration>
    <system.web>
        <machineKey>

<machineKey validationKey='...' decryptionKey='...' validation='' />

我们知道Http是无连接协议, 而Cookie可以标识特定站点的用户信息, ASP.NET在默认情况下也一样, 即使是Session在默认情况下也是基于Cookie的, 所以如果一个站点的Cookie能被另一个站点识别,不就可以...

正常情况下, ASP.NET的Forms验证一般是这样做的, 受保护页面根据权限分组放进不同的文件夹中, 然后在各自文件夹的web.config中对这些文件进行访问保护.

例如管理员访问的各个页面, 我一般会放进一个 Admin 目录中, 然后在Admin目录下的Web.config中的 <authorization> 节中配置它的访问权限,像下面这样:

<configuration>
    <system.web>
        <authorization>
            <deny users="?" /> <!--不允许匿名用户访问-->
            ...

如果某用户不幸访问了这些页面应该让页面重定向到Login.aspx中, 这需要在根目录的Web.confg中进行一些配置, 最简单的情况应该像下面这样:

<configuration>
    <system.web>
        <authentication mode="Forms">
            <forms loginUrl="~/login.aspx" />
         </authentication

题外话: 如果要对站点的图片进行访问控制,也可以像上面这么做, 因为许多站点并不想让其它用户仅仅知道地址就可以直接访问图片信息. 但是这样还不够, 需要在IIS中配置一下对图片资源的接管, 就像.aspx是由aspnet_isapi.dll处理的, 你应该让图片也经由它手.

下面就可以进行用户名/密码验证了.

if (用户名/密码验证通过) {
    System.Web.Security.FormsAuthentication.RedirectFromLoginPage(".LOGINAUTH1",
        false);
}

这样,如果你首先访问了受保护页面, 它将会重定向到登录页面中, 而你在这里登录后, 它将自动重定向到先前的受保护页面.
如果一开始你访问的就是登录页面, 那么登录后, 默认情况下, 它会将页面重定向到 default.aspx .

以上讲这么多登录的东东, 但是原本是讲单点登录的, 其实我并没有离题, 只是如果你到了这一步, 那么只需要在两个,或多个站点的WebConfig中配置一下 machineKey 就可以让其共享Cookie, 在一个站点中登录, 也就相当于在另一个站点中登录, 退出也一样.

machineKey配置节文档如下:

<machineKey
    validationKey="AutoGenerate|value[,IsolateApps]"
    decryptionKey="AutoGenerate|value[,IsolateApps]"
    validation="SHA1|MD5|3DES"
/>
 
其中 validationKey 是 用于验证加密数据的密钥, 手动配置时, 推荐用128个十六进制字符
     decryptionKey 是 用于加密数据的密钥, 这个的长度和加密类型(也就是第三个参数) 相关, 比如选 3DES 则这里是 48 个16进制字符
     validation 是 数据验证使用的加密类型

OK, 写配置节前,我们还需要两个长长的十六进制串呢, 当我用键盘敲了10几下后, 发现自己是笨蛋, 应该让脚本帮助生成的, 否则即不随机, 又慢, 而且长度还可能搞错.

如果你也用Python, 那么可以用以下语句得到128位十六进制串, 呵呵 相当的简单和方便:

import random

s = ''
for i in range(128):
    s += '%X' %(random.randint(0, 15))
else:
print s

配置节信息, 像下面这样(难看死了:()

<machineKey
validationKey="F65E3D075FFCE2AC48F6B0ABB73BA4FAC05E7F10BB
               E765520EA75F4E210126F01A62BE39B1059857
               A10A54FE210A14E7FD685A1040E8033202107424AFE2B443"
decryptionKey="C5475E1B28958DC6373DAA37C5B92CCDD94ECDF02D7A6A66"
validation="3DES"
/>

你需要在两个或多个站点上都具有相同的machineKey配置信息, 才能产生效果.

哦, 对了, 其实这种方法只能解决几个站点的登录问题, 但不能代替passport,, 想想全世界的站点配置成一样(哦, 当我没说过)

我没用过passport, 但看了看一些相关文献, 知道大概怎么回事.

就是让登录(专业一点说是身份验证)由专门的人(一个机构, 如passport)去做, 而普通站点只做服务就行了. 这样访问相当于以下流程:

1. 访问一站点(服务站点)的页面,

2. 服务站点去验证站点上问问, 该用户有没有已登录

3. 如果已登录了, 那么正常服务, 流程结束

4. 如果没有登录, 那么把该用户重定向到验证站点.

5. 用户在验证站点上验证登录, 一般也是输入用户名和密码验证

6. 验证站点将验证通过的用户重定向到先前的服务页面

请原谅, 英语不好, 看了一篇长长的东东, 就理出这点东西

其实这中间有很多技术的细节要处理, 数据的验证, 以及传递过程一定很复杂. 文中说, Passport 是采用Kerberos 认证机制来工作的(不要问我这是什么, 我也不知道).

哦,对了, 除了passport 还有一个 Liberty Alliance 组织也有个单点登录. 有空我会去再看看的.

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多