首页 新闻 会员 周边 捐助

asp.net 权限 Windows验证!

0
悬赏园豆:10 [已解决问题] 解决于 2012-09-17 09:28

现在做企业内部的MIS,一般情况下用Windows验证抓取工号(计算机名和域名)即可做到权限验证和操作记录工号,这样IIS上设置Windows身份验证就可以了,但是由于部门的特殊性,很多项目都要和外部用户(货代、报关行等)交互,所以有些功能页面不能用Windows身份验证,需要设置匿名验证,这样的话用一个系统(甚至同一个页面)就要使用不同的验证方式。

我们以前的做法是在项目中建立一个“内部”文件夹和一个“外部”文件夹,将“内部”文件夹设置成Windows验证,用于抓取计算机名和域名,“外部”文件夹设置成匿名验证。由于内部页面和外部页面的功能几乎一样,所以两个文件夹也是中的文件也差不多,这样的话感觉有点“冗余”。不知道有没有人遇到过这种情况,一般是采取什么样的解决方案呢?

Gamain的主页 Gamain | 菜鸟二级 | 园豆:357
提问于:2012-09-11 10:01
< >
分享
最佳答案
0

可以这样嘛,对所有页面启用匿名登录,然后根据需要Windows认证的页面来判断当前用户是否具有Windows Identity。

收获园豆:10
Launcher | 高人七级 |园豆:45050 | 2012-09-11 10:13

对,你说的和我们现在的做法很像。

我们现在抓取计算机名的逻辑:

string UserName = System.Web.HttpContext.Current.User.Identity.Name;
string[] strID = UserName.Split(new char[] { '\\' });

strID[0].:计算机名,strID[1]:域名。

但是如果像你说的那样直接都设置成匿名登录,而不设置Window验证登录,这段代码是不起作用的。

Gamain | 园豆:357 (菜鸟二级) | 2012-09-11 10:22

@Gamain: 你把自己的逻辑搞乱了,如果用户以Windows凭据登录,那么你就执行你抓取计算机名和域名的代码,否则啥都不做,因为你的“内部”和“外部”的功能都一样,唯一的差别,就是一个记录了操作员,另一个没记录。

如果你明白这层道理,你还有疑问的话,我是不是可以大胆猜测,你的“内部”必须通过Windows身份认证才能访问,而"外部"可以匿名访问,也就是说匿名访问的用户只有查询功能,不能删除,修改。

Launcher | 园豆:45050 (高人七级) | 2012-09-11 10:43

@Launcher:

首先,非常感谢您的解答。

我现在的问题是,如果系统所有的页面都设置成匿名登录的话还可以抓取到计算机名和域名信息吗。

比如对于同一个页面:

如果设置成匿名登录,那么内部用户还能抓取到计算机名和域名信息吗

如果设置成Windows身份验证,那么外部用户是不是就不能访问了呢?

我自己查阅了一些资料,如果要抓计算机信息的话都是要用Window验证的

http://www.cnblogs.com/fish-li/archive/2012/05/07/2486840.html

http://wuxing.blog.51cto.com/134326/52556

不知道我的理解是不是有偏差。

Gamain | 园豆:357 (菜鸟二级) | 2012-09-11 10:54

@Gamain: 内部用户访问你的页面的时候会以Windows凭据登录,也就是访问页面的时候会有个Windows凭据验证对话框,如果验证成功,Asp.Net会把凭据转换为System.Web.HttpContext.Current.User,如果失败则会得到一个IsAuthticated=false的标识。

 

你现在的问题不是抓取信息一定要Windows认证,而是你先要搞清楚你们的业务对权限的需求问题。

Launcher | 园豆:45050 (高人七级) | 2012-09-11 11:01

@Launcher: 

我们的业务逻辑是没有问题的,对应同一个页面是会有不同的角色来访问。

我可不可以这样理解你的说法:

1、所以页面都采用匿名登录

2、在页面中加上获取计算机名信息的代码。

3、由于2的原因,因此User在访问页面时候会弹出一个凭据验证对话框。

4、如果验证成功则判断为内部用户,否则判断为外部用户。

我这样理解有问题吗

Gamain | 园豆:357 (菜鸟二级) | 2012-09-11 11:34

@Gamain: 你这样理解的话,我前面诉述的方案就和你现在分内、外页面实现的功能是一致的。

Launcher | 园豆:45050 (高人七级) | 2012-09-11 11:44

@Launcher: 

恩,如果能这样的话那么就没有问题了

1、所以页面都采用匿名登录

2、在页面中加上获取计算机名信息的代码。

3、由于2的原因,因此User在访问页面时候会弹出一个凭据验证对话框。

4、如果验证成功则判断为内部用户,否则判断为外部用户。

但是我刚才有问了一下我师父,他说必须要设置成Windows身份验证才能够在做到

User在访问页面时候会弹出一个凭据验证对话框。也就是说,只设置成匿名验证是不行的。

我不知道您有没有做过类似的项目,我们实际的项目中的确是必须要使用Windows验证才能抓取到计算机名信息。也就是说如果只设置匿名验证的话一下代码是无效的:

string UserName = System.Web.HttpContext.Current.User.Identity.Name;
string[] strID = UserName.Split(new char[] { '\\' });

strID[0]:计算机名,strID[1]:域名。

(已验证不可用。如果IIS设置匿名验证的话strID 一直都是null)

如果您有更好的办法能在匿名验证下面获取到计算机名称,希望能够给点实例代码,非常感谢。

 

Gamain | 园豆:357 (菜鸟二级) | 2012-09-11 12:06

@Gamain: 如果你规定页面必须通过认证,那么未授权访问就要求认证,如果你没这样的限制,那么不用登录也能访问该页面。你可以设置一个LogOn页面,把该页面设置为必须通过认证。可以在Global.axpx中来限制,也可以在web.config中指定

<authentication mode="Forms">
      <forms loginUrl="~/Account/LogOn" timeout="2880" />
    </authentication>

你可以复习下asp.net的请求流程。

只要知道IP,就可以获取主机名,可以通过socket来,也可以采用下面的方式:

http://hi.baidu.com/fujiayu007/item/fa878d35225fff8ac2cf29e4

Launcher | 园豆:45050 (高人七级) | 2012-09-11 13:02

@Gamain: 你还是没理清你的业务的权限需求,我现在问你一个问题:现有页面A,是否已认证或未认证用户都可以访问该页面?

Launcher | 园豆:45050 (高人七级) | 2012-09-11 13:03

@Launcher: 是的,是已认证或未认证用户都可以访问该页面。

最好能实现这样的功能:

User请求该页面的时候首先做权限判定(当然,前提是登录名和密码都已经验证通过),如果验证为内部用户(可以抓到计算机名,域名)那么就给予编辑,删除的权限,同时对每一步操作都记录当前的计算机名称(在我们企业内部对应到员工的工号),如果验证为外部用过则不给予编辑,删除的权限(不如禁用、隐藏编辑框,按钮等)。

那么这个页面是不是应该设置成匿名验证,然后再通过代码的方式来获取计算机名呢?

Gamain | 园豆:357 (菜鸟二级) | 2012-09-11 19:47

@Launcher: 

非常感谢您的回复。

恩,我写写代码调试一下看看。

如果设置成匿名访问也能获取到Client端的计算机名称和计算机域名的话,那么一切问题就都解决了。

Gamain | 园豆:357 (菜鸟二级) | 2012-09-11 19:54

@Gamain: 我可以明确的告诉你,你没有弄明白 Asp.Net 的请求处理流程和安全模型。可以为页面同时启用Windows身份验证和匿名身份验证,但是这不表示访问某个页面就一定要通过Windows身份验证或不用通过Windows身份验证——请你仔细的体会这句话。所以,请不要把是否通过验证,或者是否设置了验证方式用来和能否访问某个页面直接关联起来。

Launcher | 园豆:45050 (高人七级) | 2012-09-12 09:21

@Launcher: 

谢谢您的指教。说实话我对ASP.Net的请求流程不是太了解。

今天我又向师父确认了一下,可能我以前的表述有点问题。由于整个公司的网络都是在一个域下面的,

所以我们验证权限并不是抓取计算机名,而是域账号域名

用下面的方式

string UserName = System.Web.HttpContext.Current.User.Identity.Name;
string[] strID = UserName.Split(new char[] { '\\' });

strID[0]:域账号(不一定和计算机名相同,对应到员工公工号),strID[1]:域名。

然后进入判断

1、如果strID为空(没有抓到域账号),判断为没有权限,返回。

2、如果抓取的域名和公司的域名不同,判断为没有权限,返回。

3、判断为有权限的内部用户,同时记录域账号。

和我师父确认了一下,他说问题的关键是:如果不设置Windows身份验证就抓取不到域账号和域名。

 

Gamain | 园豆:357 (菜鸟二级) | 2012-09-13 16:02

@Gamain: 

1,使用项目模板,新建一个 ASP.NET Web 应用程序;

2,修改 Web.Config,将 authentication 的 mode 属性由默认的 Forms 改为 Windows;

3,部署到IIS中;

4,在已部署网站或应用程序的“身份验证”视图中,启用“Windows 身份验证”和“匿名身份验证”;

现在你可以测试你的网站或应用程序了,进入首页后,你可以在不登录的条件下访问“主页”和“关于”两个页面;你可以点击右上角的“登录”或在未登录条件下浏览“http://www.xxx.com/WebApp/Account/ChangePassword.aspx”,这时候会弹出“Windows 安全”对话框,要求你输入Windows登录凭据。

也就是说,如果你对所有页面都没有强制要求通过验证,那么用户可以匿名访问这些页面,如上述“主页”和“关于”;如果某些页面需要授权才能访问,比如“http://www.xxx.com/WebApp/Account/ChangePassword.aspx”,由于启用了Windows身份验证,那么会自动弹出“Windows 安全”对话框。

因此,你的所有页面分成两类,一类是需要授权的,一类是不需要授权的。对于需要授权的页面来说,如果授权成功,HttpContext.Current.User 肯定就是 Windows 标识;对于不需要授权的页面来说,如果用户没有主动点击“登录”,或以其它页面触发了“登录”,那么他会以匿名方式访问,HttpContext.Current.User 则表示匿名标识,不包含用户身份信息。

不知道我讲明白了没。从你的1、2来看,你是要判断权限,实际上你的问题就回到了在ASP.NET中如何授权的问题,也就是哪些页面需要授权才能查看,当用户访问这些页面时,未授权用户会被重定向到登录页面。你在页面中来检测是可以的,但是你没有把未授权用户重定向到登录页面。其它的方式还有在某个目录下放置Web.config,在该文件中可以分配能够访问该目录下页面的用户;另外,也可以通过Global,在AuthenticateRequest 事件中根据url来确定是否重定向到登录页面。

 

最后强调一句:HttpContext.Current.User 是通过验证、授权两个步骤后才创建出来的,也就是说,当你在使用 HttpContext.Current.User 时,该用户已经经过了验证、授权步骤,你接下来可以做的事情就是根据权限需求将用户重定向到登录页面或允许用户继续访问。

Launcher | 园豆:45050 (高人七级) | 2012-09-13 17:10

@Launcher: 

非常感谢您的解答,在网络上能够遇到您这样热心的人都让我有点感动。 

最近几天有点忙,我稍后会根据您给的方法测试一下,如果成功的话以后就再也不用copy两个文件夹了。

Gamain | 园豆:357 (菜鸟二级) | 2012-09-14 12:47

@Gamain: 

非常感谢您的解答,菜鸟分少,不要介意哈。

Gamain | 园豆:357 (菜鸟二级) | 2012-09-17 09:29

@Launcher: 

非常感谢您的解答,今天我按照你的方法做了一下,发现还是有问题。

我再把我需要的权限流程说一下,如下图:

我的目的是要实现:内部用户和外部用户都能访问目标页面,而且,如果是内部用户的话,还要记录用户的客户端计算机登录名(不是计算机名也不是计算机ID,也不是Server端的计算机信息)。

那么,现在的问题是

1、如果目标页面( 或者说是目标页面所在的目录,或者整个网站)不设置成Windows身份验证,那么就获取不到客户端计算机登录名(不是计算机名也不是计算机ID,也不是Server端的计算机信息),这一点我已经验证,而且你上边的例子也有说过,需要4,在已部署网站或应用程序的“身份验证”视图中,启用“Windows 身份验证”和“匿名身份验证”;才能够获取这些信息。

2、如果目标页面( 或者说是目标页面所在的目录,或者整个网站)设置成Windows身份验证,那么外部用户就会因为没有windows身份验证而不能访问目标页面。

所以,对于同一个页面来说1和2这两点是相互冲突的。

我们以前的做法是在网站下面建立一个Internal和一个External文件夹,分别设置成windows身份验证和匿名验证,然后把目标页面分别在两个文件夹下复制一份。User请求页面时,如果判断是内部角色(如Admin)就引导到Internal目录下(由于这个目录设置了Windows身份验证,所以能获取到域名和登录信息),如果判断是外部角色(一般的角色AAA),就引导到External目录下(这个目录没有开启Windows验证,因此没有通过Windows身份验证的也能够访问。)

这样做是没有问题的,但是由于需要将一个功能相似的页面复制两份看,我感觉有点“欠妥当”,因此想找一种能够实现上面图片中的方法。

不知道我说的是不是很明白。

Gamain | 园豆:357 (菜鸟二级) | 2012-09-20 21:20

@Gamain: 把页面同时设置成支持匿名和Windows身份验证,能够保证用户既可以在不通过验证的情况下访问页面,也可以在通过验证的情况下访问页面。所以,你说的1和2冲突是不存在的。

由于你的脑子绕不过来,所以我们还是回到我开始给你讲的初级流程,我们把注意力放在“主页”这个页面,你通过调试可以发现:

1,访问“主页”这个页面的时候,并没有强制要求你登录或不登录才能访问“主页”,是吗?

2,你可以点击“登录”后,接着继续访问“主页”这个页面,是吗?

如果回答都是“是”,那么在通过“登录”后访问“主页”,是不是就能在“主页”中取到登录信息?

请注意,我说的是把同一个页面同时设置成既支持匿名身份验证,又支持Windows身份验证,这里是既又的关系,不是只支持其中一种。

Launcher | 园豆:45050 (高人七级) | 2012-09-21 09:19

@Launcher: 

很不好意思,又来打扰您。根据您上次的提示,我又做了测试,可是还是不行,如下:

代码:

     protected void Page_Load(object sender, EventArgs e)
        {
            
            lblDom.Text = TrytoGetUserId();
        }
 #region   尝试抓取用户Windows登录名和域名
        public string TrytoGetUserId()
        {
            FormsAuthentication.SetAuthCookie("<p style='color:red'>您通过了Form验证:</p>FormID", true);
            string UserName = System.Web.HttpContext.Current.User.Identity.Name;
            string[] strID = UserName.Split(new char[] { '\\' });
            if (strID.Length == 2)
            {
                string strUserID = strID[1];
                string strDomain = strID[0];
                return string.Format("<p style='color:red'>您通过了Windows身份验证:</p>登录ID:{0}        所在网域:{1}", strUserID, strDomain);
            }
            else if (strID.Length != 0)
            {
                string strTmp = "<p style='color:red'>您没有通过Windows身份验证:</p>";
                foreach (string str in strID)
                {
                    strTmp += str + "||";
                }
                return strTmp;
            }
            else
            {
                return "<p style='color:red'>您没有通过验证!</p>";
            }
        }
        #endregion

然后,把这个网站部署打server的IIS上,设置成不同的验证方式,然后在Server本机,域内计算机和域外计算机访问这个页面。(由于不涉及到Form验证,因此,不考虑这种方式)

1、禁用所有的验证方式,如我们所料,都不能访问:

Server本机,域内计算机和域外计算机都是同样的页面:

 

2、只开启匿名验证,所有的都抓取不到 Windows登录标示:

 

3、只开启Windows身份验证:

域内计算机都可以抓到Windows登录标识,域外计算机弹出身份验证框:

 

4、同时开启匿名验证和Windows验证:

情况和只开启匿名验证一样,不管是内部还是外部用户,都不能获取Windows登录标识

 

由此,我的结论是:匿名验证的优先级要高于Windows身份验证。

也就是说,如果开启了匿名验证的话,即使开启了Windows身份验证,也不能获取Windows登录标识。

 

那么,现在的问题是:

A、如果只开启匿名验证,那么就不能获取内部用户的Windows登录标识(工号)

B、如果同时开启匿名验证和Windows身份验证 由于“匿名验证优先级高于Windows身份验证”,还是有和B同样的问题。

C、如果只开启Windows身份验证,外部用户就会因为不能通过验证而不能访问页面。

 

 

Gamain | 园豆:357 (菜鸟二级) | 2012-09-25 14:35

@Gamain: 我发觉我说啥你都无法理解,我也只能手把手的教你的才行。你这几个截图很正确,跟我前面讲的原理是一致的。你需要提供一个登录页面:

<authentication mode="Windows">
      <forms loginUrl="~/Account/Login.aspx" timeout="2880" />
</authentication>

如果用户点击了该登录页面,那么他就可以看到你的 3 中的截图。你明白了吗?就是说你能不能取到Windows凭据,是由用户主动发起的,而不是你的程序来控制的。

Launcher | 园豆:45050 (高人七级) | 2012-09-25 14:43

@Gamain: 如果你想让程序来识别哪些用户必须通过登录后才能使用网站,你可以在 Global.aspx 中根据请求的IP地址来区分外网和内网,如果是内网用户且没有经过验证(颠倒过来也行),就重定向到Login.aspx;如果是外网用户,直接放行。判断外网和内网用户的依据就是他们的IP范围。

Launcher | 园豆:45050 (高人七级) | 2012-09-25 14:45

@Launcher: 

我感觉您说的我都听懂了,只是不知道如何实现,

您上次说的是 只要“同时开启 匿名验证和Windows验证” ,这样就可以做到“对外部用户直接放行,对外部用户抓取登陆凭证”,可是,根据我上面的测试,这样的确是不行的啊。

我不知道是我的测试代码有问题,还是如你刚才所说的,要达到这样的效果,就必须要“在 Global.aspx 中根据请求的IP地址来区分外网和内网”。

Gamain | 园豆:357 (菜鸟二级) | 2012-09-25 15:35

@Launcher: 

或者是,如果方便的话,您能否给我一个简单的测试项目以作示例呢?

感激不尽。

Gamain | 园豆:357 (菜鸟二级) | 2012-09-25 15:39

@Launcher: 

只要求能达到这样的要求:

有一个页面,如果是域内部用户访问 就显示 : “ 内部用户, Windows登录用户:XXX,域名:XXX”

如果是域外部用户访问,就显示:“外部用户”

Gamain | 园豆:357 (菜鸟二级) | 2012-09-25 15:44

@Gamain: 我都说的不爱说了,我就截取我以前说的话吧:“如果你对所有页面都没有强制要求通过验证,那么用户可以匿名访问这些页面,如上述“主页”和“关于”,你注意到我这句话里有个“强制”词吗?

也就是说,只要不“强制”,用户是既可以通过Windows认证后访问页面,也可以匿名访问页面。而要取得Windows凭据,那么用户就必须主动选择通过Windows认证后再访问页面(使用Login.aspx页面)。

现在看来,你必须要实现“强制”内部用户登录后才能取得Windows凭据,那么新的问题就来了,在没有登录之前如何区分“内部用户”和“外部用户”,一种最简单的实现方式就是通过访问请求的IP地址来区分“内部用户”和“外部用户”,通过IP地址,你就可以识别出当前发起请求的用户是来自内部网络还是外部网络,对于来自内部网络的用户,你就可以将其重定向到“Login.aspx”页面,这样“内部用户”就被强制进行了Windows验证,从而你也可以读取到“内部用户”的Windows凭据信息了。

Launcher | 园豆:45050 (高人七级) | 2012-09-25 15:50

@Gamain: 现在要示例已经晚了,你要是一开始就只要示例,我就给了,省得跟你讲这么多你理解不了原理。

Launcher | 园豆:45050 (高人七级) | 2012-09-25 15:53

@Launcher: 

%>_<%,以前在网上提问,说道要示例代码,就有人说“方法都说了,代码自己写,要靠自己动手”。

我开始没有要代码,就怕你也会来这一句.....

Gamain | 园豆:357 (菜鸟二级) | 2012-09-25 16:04

@Launcher: 

你如果早点告诉我,“只能够通过IP网段来区分内部用户和外部用户的话",我也不会再这个问题上纠结这么久了。

我对身份验证这一段了解甚少,谢谢您的指点。

Gamain | 园豆:357 (菜鸟二级) | 2012-09-25 16:06

@Gamain: 关于使用IP来区分内部用户和外部用户的方法我在前面也已经说过了。这个需求的解题思路很简单:

1,匿名用户能够访问系统,网站必须支持匿名认证;

2,能够获取“内部用户”的Windows凭据信息  ,网站必须支持Windows身份认证;

实现:以上两项需求通过简单配置就能实现。

3,必须获取“内部用户”的Windows凭据信息。

此项需要把问题分解:

3.1,由于通过Windows认证是获取Windows凭据的前提,因此,“内部用户”必须通过Windows认证后才能访问系统;

实现:通过在Global.aspx中将未认证的“内部用户”重定向到Login.aspx页面,可以强制“内部用户”通过Windows认证;

3.2,要指定“内部用户”必须通过Windows认证后才能访问系统,则首先需要找到鉴别“内部用户”的方法;

实现:通过IP段可以简单鉴别“内部用户”;

 

也就是说,我把所有原理都给你讲了一遍,但是,你却没有解题的思路,这和做数学应用题一样,所有原理你都学了,但是你却不理解题意。

Launcher | 园豆:45050 (高人七级) | 2012-09-25 16:51

@Launcher: 

我明白您的意思,我用下面的图来描述应该没错吧

Gamain | 园豆:357 (菜鸟二级) | 2012-09-25 17:58

@Gamain: 流程基本正确,差了一步,在根据IP判断之前,先检查用户是否已经经过了验证,因为通过验证后,下次请求会有Session信息携带,就可以直接认为是“内部用户”。

Launcher | 园豆:45050 (高人七级) | 2012-09-25 18:04

@Launcher: 

恩 ,这样的确是一种方法。

但是和我的需求可能还有点出入,可能我以前没有说过。

我真实的目的是想用AOP的方式为MVC项目写一个比较通用的权限控制框架。

在Controller中的每个方法前面都加上“ [UserAuthorize(AllowUser = "Admin")]”这样的特性,以达到对每个请求,在执行前都做一次权限验证。

这样的话,也不可能在每次相应请求的时候都引导到Login.aspx页面吧。

Gamain | 园豆:357 (菜鸟二级) | 2012-09-26 08:58

@Gamain: 

其实我比较迷惑的是,Login.aspx页面是如何抓取Windows凭证的,我所有的页面都设置的是同样的验证方式,为什么就只是Login.aspx页面能够抓取到登录信息呢?

既然Login页面能够获取这些信息,是不是意味着我其他的页面也一样能和实现这样的效果呢?

也就是说,我在每个页面都试着抓取Windows凭证,如果抓取成功,就认为是内部用户,否则就是外部用户,这样的话不就是不用引导到Login页面吗,而且还可以做到对每个页面都进行权限验证。

但是,我翻了源代码,并没有在Login页面找到任何与“抓取权限”相关的代码。

Gamain | 园豆:357 (菜鸟二级) | 2012-09-26 09:11

@Gamain: Login.aspx是个登录页面,让用户可以输入登录凭据的页面,如果设置为Forms认证,此页面可以匿名访问,不然用户没法输入用户名和密码;如果设置为Windows认证,那么Asp.Net的认证流程会在访问Login.aspx页面之前先弹出Windows安全对话框,为什么这里只有Login.aspx会弹出此对话框呢?因为在配置文件中指明了的:

<authentication mode="Windows">
<forms loginUrl="~/Account/Login.aspx" timeout="2880" />
</authentication>

因为你的页面既要能匿名访问,又要能通过Windows认证后访问,那么你就不能把每个页面都指定为必须通过Windows认证,而要在页面中取到Windows凭据,你就只能通过经过了Windows认证后的请求上下文来获取,因此我们才在Global.aspx中把没有通过认证的内部用户重定向到Login.aspx,当内部用户通过Login.aspx输出用户名和密码并通过认证后,那么当前请求上下文就包含了内部用户的Windows凭据信息,以后内部用户的请求就会携带着这些信息去访问你的其它页面,从而你也就能在你的页面中拿到这些信息了。

如果你要使用AOP的话,我们依然有多种解决方案来实现你这个特殊的权限控制(还是请你注意我上面回答中提到的3点需求):

一,在Global.aspx中通过身份模拟,为外部用户模拟一个特定的用户身份(所有外部用户使用同一个用户名和角色),这样你的AOP就能允许所有外部用户在不登录(通过Login.aspx认证)的状态下正常访问你的所有页面。

二,由于默认的授权规则只允许UserAuthorize中标识的用户(注意,这里没有内外之分)访问Contoller,所以,你需要自定义授权管理,允许没有通过认证的外部用户(注意,这里是外部用户)和UserAuthorize中标识的内部用户(注意,这里是内部用户)访问你的Controller。

不是每次请求都引导到Login.aspx页面,而是没有经过认证的内部用户(注意,这里有内部用户字样)才重定向到Login.aspx页面。

 

“我在每个页面都试着抓取Windows凭证,如果抓取成功,就认为是内部用户,否则就是外部用户”,这是不对的,要获取Windows凭据(准确的说应该是令牌),就必须先通过认证。没有通过认证的请求,你只能通过IP来判断是内部用户,还是外部用户。

 

我不得已把前面讲过的话又换了种方式说出来,我个人感到很无奈。因此,为了让你真正的理解ASP.NET的安全机制,我建议你自己多写代码,多调试,把Session,Cookie,IIdentity,IPrincipal等概念搞清楚。

Launcher | 园豆:45050 (高人七级) | 2012-09-26 11:26

@Launcher: 

非常感谢您的解答,这次我是真的明白了。

其实Login.aspx页面实现的只是一个授权功能,在此之后内部用户的页面权限验证都是检查授权是否存在,如果存在就放行请求,如果不存在,就重定向到Login页面。

我以前所理解的“尝试抓取Windows凭证”的感念是错误的。

整体思路我是有了,剩下的就是编码部分了。对我来说一个难点可能就是如何让Login页面对用户来说是“透明”的,也就是说在内部用户输入账号密码后,能不能不要“显示”的来定向到Login页面,而是后台通过代码进行授权。可惜的是实例项目中授权这一块使用一个登陆控件完成的,我看不到实现原理,而我的项目中是可能使用登录控件的。

再次感谢您的帮助。

Gamain | 园豆:357 (菜鸟二级) | 2012-09-26 13:04

@Launcher: 

我又做了测试,发现实际情况和你说的还是有一点出入的

那么Asp.Net的认证流程会在访问Login.aspx页面之前先弹出Windows安全对话框,为什么这里只有Login.aspx会弹出此对话框呢?因为在配置文件中指明了的:

<authentication mode="Windows">
<forms loginUrl="~/Account/Login.aspx" timeout="2880" />
</authentication>

经过测试,发现其实不是这个配置导致会抓取身份验证,

而是因为Account文件夹里面多了一个配置文件,限制了只有授权用户才能访问这个目录。

 

<?xml version="1.0" encoding="utf-8"?>
<configuration>

  <location path="Register.aspx">
    <system.web>
      <authorization>
        <allow users="*"/>
      </authorization>
    </system.web>
  </location>

  <system.web>
    <authorization>
      <deny users="?"/>
    </authorization>
  </system.web>

</configuration>

 

正是由于这个配置文件,导致当用户访问这个目录下的页面时候
如果是内部用户,那么就直接授权,如果是外部用户,那么就会弹出Windows身份验证窗体。

 

因此,在Account文件夹下面放一个页面,只是起到“授权”的作用,经过授权后就可以以“内部用户”的身份来访问其他目录的页面了。

Gamain | 园豆:357 (菜鸟二级) | 2012-09-26 15:34

@Gamain: 你描述的很正确,我疏忽了这点,不过这也说明我之前写的帖子你都没认真看过。

Launcher | 园豆:45050 (高人七级) | 2012-09-26 16:00

@Launcher: 

恩,开始的时候我没有理解你说这句话的意思,现在知道了。

Gamain | 园豆:357 (菜鸟二级) | 2012-09-26 16:13
其他回答(2)
0

如果是全部都使用匿名验证会有什么不好吗,安全方面?

jason2013 | 园豆:1998 (小虾三级) | 2012-09-11 10:04

如果是内部用户的话需要抓取记录工号(也就是计算机名和域名),如果用你们验证的话就抓不到这些信息。吧!

支持(0) 反对(0) Gamain | 园豆:357 (菜鸟二级) | 2012-09-11 10:10

我们内部以一套OA身份系统,通过计算机名是可以定位到具体员工的。

我们现在的做法是:

比如有一个编辑页面,在”内部“和”外部“页面各Copy一份,而且在”内部“中的代码中加上抓取计算机名称和域名的逻辑。当User登录时候,如果是内部账号(比如管理员账号Admin),就会被引导到”内部“的页面,如果是外部账号(比如一般账号”AAA“)就会被引导到”外部“的页面,而事实上这两个页面功能完全相同,唯一不同是就是”内部“的页面多了一段抓取计算机名的逻辑,这样的话就可以记录到具体的操作员工了。

我们现在的做法是开发的时候直接开发内部页面,测试后再copy到”外部“文件夹中,最一点点逻辑修改就OK了。但是感觉有点怪怪的。

不知道我说的够不够清晰。

支持(0) 反对(0) Gamain | 园豆:357 (菜鸟二级) | 2012-09-11 10:16
0

一个看起来毫不起眼的权限验证,竟然隐藏这么大的学问,收藏了

凡的世界 | 园豆:204 (菜鸟二级) | 2019-10-11 14:28
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册