您的位置:知识库 »

.net中的认证(authentication)与授权(authorization)

作者: 菩提树下的杨过  来源: 博客园  发布时间: 2010-08-30 22:25  阅读: 9218 次  推荐: 4   原文链接   [收藏]  
摘要:在.net中提供了强大的用户认证和授权机制,不管是在b/s和c/s中都会有相关的使用,这篇文章给大家介绍分别在b/s和c/s中的简单使用。
[1] .net中的认证(authentication)与授权(authorization)
[2] .net中的认证(authentication)与授权(authorization)

  “认证”与“授权”是几乎所有系统中都会涉及的概念,通俗点讲:

  1、认证(authentication) 就是 "判断用户有没有登录?",好比windows系统,没登录就无法使用(不管你是用Administrator或Guest用户,总之要先正确登录后,才能进入系统)。

  2、授权(authorization) 就是"用户登录后的身份/角色识别",好比"管理员用户"登录windows后,能安装软件、修改windows设置等所有操作,而Guest用户登录后,只有做有限的操作(比如安装软件就被禁止了)。

   .net中与"认证"对应的是IIdentity接口,而与"授权"对应的则是IPrincipal接口,这二个接口的定义均在命名空间System.Security.Principal中: 

using System;
using System.Runtime.InteropServices;

namespace System.Security.Principal
{
[ComVisible(
true)]
public interface IIdentity
{
string AuthenticationType { get; }
bool IsAuthenticated { get; }
string Name { get; }
}
}

using System;
using System.Runtime.InteropServices;

namespace System.Security.Principal
{
[ComVisible(
true)]
public interface IPrincipal
{
IIdentity Identity {
get; }
bool IsInRole(string role);
}
}
应该注意到:IPrincipal接口中包含着一个只读的IIdentity,这也跟最开始提到的概念一致:识别身份的前提是先登录,只有登录成功后能进一步确认身份。

  用Membership/Role做过asp.net开发的朋友们,看到这二个接口的定义,应该会觉得很眼熟,想想我们在Asp.Net页面中是如何判断用户是否登录以及角色的?

protected void Page_Load(object sender, EventArgs e)
{
HttpContext ctx
= HttpContext.Current;
if (ctx.User.Identity.IsAuthenticated && ctx.User.IsInRole("管理员"))
{
//管理员该做的事,就写在这里
}
else
{
//Hi,您不是管理员,别胡来!
}
}

  这段代码再熟悉不过了,没错!membership/role的原理就是基于这二个接口的,如果再对HttpContext.Current.User刨根问底,能发现下面的定义:

  即:HttpContext.Current.User本身就是一个IPrincipal接口的实例。有了上面的预备知识,可以直奔主题了,先来一个Console控制台程序测试一下用法:

using System;
using System.Security.Principal;
using System.Threading;

namespace ConsoleTest
{
class Program
{
static void Main(string[] args)
{

GenericIdentity _identity
= new GenericIdentity("菩提树下的杨过");
GenericPrincipal _principal
= new GenericPrincipal(_identity, new string[] {"管理员","网站会员" });

Thread.CurrentPrincipal
= _principal;//并非必需,但在winform程序中有很用(后面会提到)

string loginName = _principal.Identity.Name;
bool isLogin = _principal.Identity.IsAuthenticated;
bool isAdmin = _principal.IsInRole("管理员");
bool isWebUser = _principal.IsInRole("网站会员");

Console.WriteLine(
"当前用户: {0}", loginName);
Console.WriteLine(
"是否已经登录? {0}", isLogin);
Console.WriteLine(
"是否管理员? {0}", isAdmin);
Console.WriteLine(
"是否网站会员? {0}", isWebUser);

Console.Read();
}
}
}

  输出如下:

当前用户: 菩提树下的杨过
是否已经登录? True
是否管理员? True
是否网站会员? True

  一切正常,没什么大不了,但Console默认只是一个单线程的程序,也没有丰富的GUI界面,所以...这个只不过是热身,看下接口定义的几个方法是否管用而已。

  这二个接口同样也能用在Winform程序中,下面将创建一个WinForm应用,里面有二个窗口:Form1以及Form2,可以把Form1当成登录界面,而Form2则是程序主窗口,在很多管理软件中,主窗口都要求登录以后才能访问,我们就来模拟一下:

  Form1的界面:

  Form2更简单:(就一个只读的TextBox)

  我想做的事情:在Form1上登录后,看看在Form2中,能否判断出用户已经登录,以及识别出身份。

  Form1 中的代码:

using System;
using System.Security.Principal;
using System.Threading;
using System.Windows.Forms;

namespace WinformTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void btnLogin_Click(object sender, EventArgs e)
{
if (txtUserName.Text.Trim() == "") {
MessageBox.Show(
"请输入用户名!");
txtUserName.Focus();
return;
}

IIdentity _identity
= new GenericIdentity(txtUserName.Text.Trim());
IPrincipal _principal
= new GenericPrincipal(_identity, new string[] { "管理员" });

Thread.CurrentPrincipal
= _principal;//将其附加到当前线程的CurrentPrincipal

MessageBox.Show(
"登录成功!");
}

private void btnShow_Click(object sender, EventArgs e)
{
(
new Form2()).ShowDialog();
}

private void btnLogOut_Click(object sender, EventArgs e)
{
Thread.CurrentPrincipal
= null;
MessageBox.Show(
"已经退出!");
}
}
}

  Form2中的代码:

using System;
using System.Security.Principal;
using System.Threading;
using System.Windows.Forms;

namespace WinformTest
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}

private void Form2_Load(object sender, EventArgs e)
{
IPrincipal _principal
= Thread.CurrentPrincipal;

if (_principal.Identity.IsAuthenticated)
{
this.textBox1.Text = "您已经登录,当前用户:" + _principal.Identity.Name;
this.textBox1.Text += Environment.NewLine + "当前角色:" + (_principal.IsInRole("管理员") ? "管理员" : "非管理员");
}
else
{
this.textBox1.Text = "您还没有登录";
}
}
}
}

  测试一下:如果在未登录的情况下,直接点击"Show窗体2",结果如下。

  如果输入用户名,并点击"登录"后,再点击"Show窗体2",结果如下:

  很理想!Form2中直接就能判断用户是否登录,以及当前登录用户的角色。这里有一个关键的细节:

Thread.CurrentPrincipal = _principal;//将其附加到当前线程的CurrentPrincipal

  在Form1中,将登录后的_principal附加到当前线程的CurrentPrincipal,我们知道:每个程序不管它是不是多线程,总归是有一个默认的主线程的。所以只要把主线程的CurrentPrincipal与登录后的_principal关联起来后,其它任何窗体,都可以直接用它来做判断,如果判断通过,则可以这样或那样(包括创建多线程进行自己的处理),如果判断不通过,则可以拒绝继续操作。

  Winform的问题解决了,再来考虑一下Webform,当然,你可以直接使用从Asp.Net2.0就支持的membership/role机制,但membership/role默认只支持sqlserver数据库(通过membership provider for oracle也可以支持oracle,但总有一些数据库不被支持,比如access、mysql、sqlite、db2等),假如你不想把用户名/密码这类信息保存在sqlserver中(甚至不想保存在数据库中,比如:xml),这时候就得开动脑筋了。

  其实...就算不用membership/role,上面提到的这二个接口仍然是可以使用的,但有一个问题:winform中,IPrincipal接口的实例可以一直存储在内存中(直到程序退出),所以其它窗口就能继续访问它,以便做进一步的判断,但是在webform中,页面本身是无状态的,一旦服务器输出html到客户端浏览器后,客户端的页面就与服务器再无瓜葛了(你甚至可以离线浏览,前提是不刷新),那么最后的认证信息保存在什么地方呢?

[第1页][第2页]
4
0

热门文章

    最新文章

      最新新闻

        热门新闻