.net中的認證(authentication)與授權(authorization)

作者: 菩提樹下的楊過  來源: 博客園  發布時間: 2010-08-30 22:25  閱讀: 8047 次  推薦: 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
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()