国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > .NET > 正文

ASP.NET基于角色的窗體安全認證機制

2024-07-10 13:10:37
字體:
供稿:網(wǎng)友
  • 本文來源于網(wǎng)頁設(shè)計愛好者web開發(fā)社區(qū)http://www.html.org.cn收集整理,歡迎訪問。
  •   說明:兩個月前我剛學(xué) asp.net, 在 codeproject.com 看到題目叫 role-based security with forms authentication 的文章,覺得很有幫助。當(dāng)時就想翻譯成中文。不過直接翻譯實在沒意思,這兩天我參照 heath stewart的這篇文章,并且根據(jù)自己的理解,把它按照自己的想法和表達方式寫成中文。附帶上自己為這篇文章做的一個演示的web應(yīng)用程序。

      如果有理解錯誤的地方,歡迎來信指出或發(fā)表評論。

      概要:

      asp.net 提供了基于角色(即 roles)的認證機制,然而它對角色的支持是不完全的。本文試圖通過一些例子來說明如何實現(xiàn)和使用這種基于角色的認證機制。

      簡介:

      asp.net 中窗體認證是一個功能非常強大的特性,只需要很少的代碼就可以實現(xiàn)一個簡單的平臺無關(guān)的安全認證系統(tǒng)。

      但是,如果你需要一個更復(fù)雜更有效的認證機制,那么你就要把眾多用戶分成用戶群組,以利用它的靈活性。windows 集成認證提供了這種認證機制,但它使用的是 ntlm,即windows nt lan manager,因而它不是跨平臺的。現(xiàn)在越來越多的人使用 linux 系統(tǒng),而 mozilla forefox 瀏覽器用戶也越來越多,我們肯定不能把這些人拒之門外,因此我們尋求另外的認證機制。有兩個選擇:一是為網(wǎng)站劃分多個區(qū)域,提供多個登錄頁面,強迫用戶一個一個的去注冊和登錄;二是把用戶分組,并且限制特定用戶組對某頁面或者某區(qū)域訪問的權(quán)限。后者當(dāng)然是更好的選擇。通過分配角色給各個用戶,我們能夠?qū)崿F(xiàn)這種功能。

      微軟為.net平臺留下了窗體認證中基于角色的認證機制,但是我們必須自己去實現(xiàn)它。本文力求覆蓋窗體認證中基于角色的認證機制的一些基本的東西,比如它的概念,它的實現(xiàn),如何在web應(yīng)用程序中應(yīng)用等。


      必要準備:

      我們首先要建立一個數(shù)據(jù)庫,一個web應(yīng)用項目,幾個不同安全級別的機密目錄,以及幾個asp.net頁面。當(dāng)然你也可以在你現(xiàn)有的web應(yīng)用項目中添加這些。

      1、創(chuàng)建數(shù)據(jù)庫

      首先要選擇你需要使用的數(shù)據(jù)庫管理系統(tǒng) dbms。本文使用 sql server 2000。

      在實際應(yīng)用項目的數(shù)據(jù)庫中,一般都會有用戶數(shù)據(jù)表 users,它可能包括用戶唯一標(biāo)記:userid,用戶名:username,密碼:password,用戶的郵件地址:email,用戶所在城市:city,用戶登錄次數(shù) logincount 等。可以通過創(chuàng)建一個 userinroles 數(shù)據(jù)表(一般可以包括兩個字段,用戶名:username,用戶角色:userroles)來實現(xiàn)為用戶分配角色。

      為了簡單,我只創(chuàng)建一個 users 數(shù)據(jù)表,它有3個字段,用戶名 username,密碼 password,用戶角色 userroles。創(chuàng)建表之前,你要選擇數(shù)據(jù)庫,或者創(chuàng)建一個新的數(shù)據(jù)庫。要創(chuàng)建一個新的命名為websolution的數(shù)據(jù)庫 ,只需要簡單的sql語句:

    create database websolution
    go

      要選擇一個叫msdb的數(shù)據(jù)庫,可以使用sql語句:

    use msdb
    go

      接下來,我們創(chuàng)建剛才提到的 users 數(shù)據(jù)表,sql 腳本如下:

    create table users
    (
    username nvarchar(100) constraint pk_username primary key,
    password nvarchar(150),
    userroles nvarchar(100)
    )

      可以為這個表創(chuàng)建索引 credentials,sql語句如下:

    create index credentials on users
    (
    username,
    password
    )

      是否創(chuàng)建索引是可選的,由你自己決定。索引的好處和壞處請參考相關(guān)資料。

      然后我們?yōu)檫@個users數(shù)據(jù)庫添加數(shù)據(jù)。角色名稱由你自己自由選擇,但是最好用有意義的名稱,比如"administrator"(頂級管理員),"manager"(管理員),"member"(加盟成員),"user"(普通用戶)等。例如:

    username|password|roles
    "willmove"|"pwd123"|"administrator,user"
    "amuhouse"|"pwd123"|"user"

      其sql語句是:

      --注意 '45cb41b32dcfb917ccd8614f1536d6da' 是 'pwd123' 使用 md5 加密后的字符串

    insert into users(username,password,userroles) values ('willmove','45cb41b32dcfb917ccd8614f1536d6da','administrator,user')
    go
    insert into users(username,password,userroles) values ('amuhouse','45cb41b32dcfb917ccd8614f1536d6da','user')
    go

      要注意的是角色 roles 是大小寫敏感的,這是因為在 web.config 文件中是大小寫敏感的。現(xiàn)在我們?yōu)閷崿F(xiàn)這個安全認證機制創(chuàng)建幾個必要的頁面。

      首先是用戶登錄頁面 login.aspx

      如果還沒有創(chuàng)建web應(yīng)用程序,那就現(xiàn)在創(chuàng)建一個。當(dāng)然你也可以在一個已有的web應(yīng)用程序中創(chuàng)建這個頁面。這里我假設(shè)已經(jīng)創(chuàng)建了一個名稱為 rolebasedauth的web應(yīng)用程序(即 visual studio .net 中的project)。我把這個login.aspx放在它的根目錄下,也就是通過 http://localhost/rolebasedauth/login.aspx 可以訪問。

      這個login.aspx放在哪里是無所謂的,但是它必須是公眾有權(quán)限訪問的。

      在應(yīng)用程序根路徑下,我們創(chuàng)建兩個機密的子目錄,分別是 admin 和 user。

      接下來,我們創(chuàng)建一個支持角色認證的窗體認證登錄系統(tǒng)。因為微軟沒有提供簡單的實現(xiàn)機制,我們要自己花些時間去創(chuàng)建認證票據(jù)。它需要存貯少量信息,當(dāng)然,有些名稱必須和 web.config 中配置的一樣,要不asp.net 就會認為你的認證票據(jù)是無效的,從而強制轉(zhuǎn)向到登錄頁面。我們在 vs.net 中為 login.aspx 添加兩個textbox控件,取名 usernametextbox, passwordtextbox,再添加一個button,取名 loginbutton,點擊它進入后臺代碼。在 loginbutton_click 方法中添加需要的代碼。如下:

    private void loginbutton_click(object sender, system.eventargs e)
            {
                // 初始化 formsauthentication
                // 注意它是在 system.web.security 命名空間
                // 因此要在代碼開始添加 using system.web.security;
                formsauthentication.initialize ();

                // 創(chuàng)建數(shù)據(jù)庫連接和數(shù)據(jù)庫操作命令對象
                // 注意它是在 system.data.sqlclient 命名空間
                // 因此要在代碼開始處添加 using system.data.sqlclient;
                sqlconnection conn =
                    new sqlconnection("data source=sun-willmove;integrated security=sspi;initial catalog=websolution;");
                sqlcommand cmd = conn.createcommand();
                cmd.commandtext = "select userroles from users where [email protected] " +
                    "and [email protected]";
                // 填充各個參數(shù)
                cmd.parameters.add("@username", sqldbtype.nvarchar, 100).value =
                    usernametextbox.text;
                cmd.parameters.add("@password", sqldbtype.nvarchar, 150).value =
                    formsauthentication.hashpasswordforstoringinconfigfile(
                    passwordtextbox.text, "md5"); // 或者 "sha1"

                // 執(zhí)行數(shù)據(jù)庫操作命令
                conn.open();
                sqldatareader reader = cmd.executereader();
                if (reader.read())
                {
                    // 為了實現(xiàn)認證,創(chuàng)建一個新的票據(jù)
                    formsauthenticationticket ticket = new formsauthenticationticket(
                        1, // 票據(jù)版本號
                        usernametextbox.text, // 票據(jù)持有者
                        datetime.now, //分配票據(jù)的時間
                        datetime.now.addminutes(30), // 失效時間
                        true, // 需要用戶的 cookie
                        reader.getstring(0), // 用戶數(shù)據(jù),這里其實就是用戶的角色
                        formsauthentication.formscookiepath);//cookie有效路徑

                    //使用機器碼machine key加密cookie,為了安全傳送
                    string hash = formsauthentication.encrypt(ticket);
                    httpcookie cookie = new httpcookie(
                        formsauthentication.formscookiename, // 認證cookie的名稱
                        hash); //加密之后的cookie

                    //將cookie的失效時間設(shè)置為和票據(jù)tikets的失效時間一致
                    if (ticket.ispersistent) cookie.expires = ticket.expiration;

                    //添加cookie到頁面請求響應(yīng)中
                    response.cookies.add(cookie);

                    // 將用戶轉(zhuǎn)向到之前請求的頁面,
                    // 如果之前沒有請求任何頁面,就轉(zhuǎn)向到首頁
                    string returnurl = request.querystring["returnurl"];
                    if (returnurl == null) returnurl = "./";

                    // 不要調(diào)用 formsauthentication.redirectfromloginpage 方法,
                    // 因為它會把剛才添加的票據(jù)(cookie)替換掉
                    response.redirect(returnurl);
                }
                else
                {
                    // 不要告訴用戶"密碼錯誤",這樣等于給了入侵者一個機會,
                    // 因為他們知道了他們輸入的用戶名是存在的
                    //
                    errorlabel.text = "用戶名或者密碼錯誤,請重試!";
                    errorlabel.visible = true;
                }

                reader.close();
                conn.close();
            }

      前臺 aspx 頁面代碼如下:

    <%@ page language="c#" codebehind="login.aspx.cs" autoeventwireup="false" inherits="rolebasedauth.login" %>
    <!doctype html public "-//w3c//dtd html 4.0 transitional//en" >
    <html>
    <head>
    <title>login</title>
    <meta name="generator" content="microsoft visual studio .net 7.1">
    <meta name="code_language" content="c#">
    <meta name="vs_defaultclientscript" content="javascript">
    <meta name="vs_targetschema" content="http://schemas.microsoft.com/intellisense/ie5 ">
    </head>
    <body>
    <form id="form1" method="post" runat="server">
    <p>
    <asp:label id="label1" runat="server">用戶名:</asp:label>
    <asp:textbox id="usernametextbox" runat="server"></asp:textbox></p>
    <p><font face="宋體">  </font>
    <asp:label id="label2" runat="server">密碼:</asp:label>
    <asp:textbox id="passwordtextbox" runat="server" textmode="password"></asp:textbox></p>
    <p>
    <asp:label id="errorlabel" runat="server" visible="false"></asp:label></p>
    <p>
    <asp:button id="loginbutton" runat="server" text="登錄"></asp:button></p>
    </form>
    </body>
    </html>

      你會注意到上面我們對密碼的處理:將它哈希加密。哈希加密是一種單向算法(不可逆算法),生成唯一的字符數(shù)組。因此即使是改變密碼中一個字母的大小寫,都會生成完全不同的哈希列。我們把這些加密的密碼存儲在數(shù)據(jù)庫中,這樣更安全。在實際應(yīng)用中,你可能想為用戶找回忘記的密碼。但是哈希散列是不可逆的,所以你就不可能恢復(fù)原來的密碼。但是你可以更改用戶的密碼,并且把這個更改后的密碼告訴他。如果一個網(wǎng)站能夠給你舊密碼,那么你要考慮清楚了,你的用戶數(shù)據(jù)是不安全的!事實上,國內(nèi)大部分網(wǎng)站都是沒有經(jīng)過加密直接把用戶的密碼存儲到數(shù)據(jù)庫中的。如何一個黑客入侵成功,那么這些用戶帳戶就很危險了!

      如果沒有使用ssl,你的密碼在網(wǎng)絡(luò)中也是以明文傳輸?shù)摹鬏斶^程中可能會被竊取。在服務(wù)器端加密密碼只能保證密碼存儲的安全。ssl相關(guān)的資料可以在 http://www.versign.comhttp://www.thewte.com 中找到。

      如果你不想以加密方式在數(shù)據(jù)庫中存儲密碼,你可以更改上面的代碼,把
    formsauthentication.hashpasswordforstoringinconfigfile(passwordtextbox.text, "md5") 改成 passwordtextbox.text 即可。

      下一步,我們需要修改 global.asax 文件。如果你的web應(yīng)用程序沒有這個文件,請右鍵單擊web應(yīng)用項目,選擇 "添加->添加新項...->global application class"。在 global.asax 或者 global.asax.cs 中,找到叫做 application_authenticationrequest 的方法(函數(shù))。先要確認已經(jīng)包含或者使用了 system.security.principal 以及 system.web.security 命名空間,然后修改它,修改后的代碼:

    protected void application_authenticaterequest(object sender, eventargs e)
    {
        if (httpcontext.current.user != null)
        {
            if (httpcontext.current.user.identity.isauthenticated)
            {
                if (httpcontext.current.user.identity is formsidentity)
                {
                    formsidentity id =
                        (formsidentity)httpcontext.current.user.identity;
                        formsauthenticationticket ticket = id.ticket;

                    // 取存儲在票據(jù)中的用戶數(shù)據(jù),在這里其實就是用戶的角色
                    string userdata = ticket.userdata;
                    string[] roles = userdata.split(',');
                    httpcontext.current.user = new genericprincipal(id, roles);
                }
            }
        }

    }

      認證票據(jù)(用戶名和密碼)是沒有作為cookie的一部分來存儲的,而且也不可以,因為用戶可以修改他們的cookie。

      事實上,formsauthentication是用你的機器碼 (machine key,通常在 machine.config 中)來加密票據(jù)(formsauthenticationticket)的。我們使用 userdata 存儲用戶角色,并且生成一個新的憑證。一旦憑證已經(jīng)創(chuàng)建,它會被添加到當(dāng)前上下文中(即 httpcontext),這樣就可以用它來取回用戶角色了。

      接下來,我們設(shè)置機密目錄(也就是"安全目錄",特定的使用者如管理員才有權(quán)限訪問的目錄)。首先看看你的web應(yīng)用程序根目錄下是否有 web.config 這個文件,如果沒有就創(chuàng)建一個。你也可以在你的子目錄中創(chuàng)建 web.config 文件,當(dāng)然,這個 web.config 文件是有限制的(一些參數(shù)它不可以設(shè)置)。要實現(xiàn)安全認證,在 web應(yīng)用程序根目錄下的 web.config 文件中找到 <system.web> 節(jié)點下的

    <authentication mode="windows" />,把它修改為

    <authentication mode="forms">
    <forms name="amuhouse.aspxauth"
    loginurl="login.aspx"
    protection="all"
    path="./" />
    </authentication>
    <authorization>
    <allow users="*"/>
    </authorization>

      上面的 name="amuhouse.aspxauth" 中,amuhouse.aspxauth 這個名稱是任意的。要控制用戶或者用戶組的權(quán)限,我們可以有兩種方法,一是配置在應(yīng)用程序根目錄下的 web.config 文件,二是在機密目錄下創(chuàng)建一個獨立的 web.config 文件。(后者也許會比較好。)如果是前者,這個web.config 就應(yīng)該包含有下面的內(nèi)容(或者類似的內(nèi)容):

    <configuration>
      <system.web>
        <authentication mode="forms">
          <forms name=" amuhouse.aspxauth"
            loginurl="login.aspx"
            protection="all"
            path="/"/>
        </authentication>
        <authorization>
          <allow users="*"/>
        </authorization>
      </system.web>
    <location path="./admin">
      <system.web>
        <authorization>
          <!-- 注意!下面幾行的順序和大小寫是非常重要的! -->
          <allow roles="administrator"/>
          <deny users="*"/>
        </authorization>
      </system.web>
    </location>
    <location path="./user">
      <system.web>
        <authorization>
          <!-- 注意!下面幾行的順序和大小寫是非常重要的! -->
          <allow roles="user"/>
          <deny users="*"/>
        </authorization>
      </system.web>
    </location>
    </configuration>

      為了使web應(yīng)用程序的目錄之前不互相依賴,可以比較方便的改名或者移動,可以選擇在每一個安全子目錄下配置單獨的 web.config 文件。它只需要配置 <authorization/>節(jié)點,如下:

    <configuration>
    <system.web>
    <authorization>
    <!-- 注意!下面幾行的順序和大小寫是非常重要的! -->
    <allow roles="administrator"/>
    <deny users="*"/>
    </authorization>
    </system.web>
    </configuration>

      需要再次提醒的是,上面的角色 roles 是大小寫敏感的,為了方便,你也可以把上面修改為:

    <allow roles="administrator,administrator" />

      如果你想允許或者禁止多個角色對這個目錄的訪問,可以用逗號隔開,如:

    <allow roles="administrator,member,user" />
    <deny users="*" />

      至此,我們已經(jīng)為網(wǎng)站配置了基于角色的安全認證機制了。你可以先編譯你的程序,然后嘗試訪問一個機密目錄,例如 http://localhost/rolebasedauth/admin ,這時候你就會被轉(zhuǎn)向到用戶登錄頁面。如果你登錄成功,并且你的角色對這個目錄有訪問權(quán)限,你就重新回到這個目錄下。可能會有用戶(或入侵者)企圖進入機密目錄,我們可以使用一個 session 來存儲用戶登錄的次數(shù),超過一定次數(shù)就不讓用戶登錄,并且顯示"系統(tǒng)拒絕了你的登錄請求!"。

      下面,我們討論如何根據(jù)用戶角色讓web控件顯示不同內(nèi)容。

      有時候根據(jù)用戶的角色來顯示內(nèi)容比較好,因為你可能不想為那么多不同的角色(用戶群組)制作一大堆有許多重復(fù)內(nèi)容的頁面。這樣的網(wǎng)站,各種用戶帳戶可以并存,付費的用戶帳戶能夠訪問附加的付費內(nèi)容。另一個例子是一個頁面將顯示一個 "進入后臺管理" 按鈕鏈接到后臺管理頁面如果當(dāng)前用戶是 "administrator"(高級管理員)角色。我們現(xiàn)在就實現(xiàn)這個頁面。

      我們上面用到的 genericprincipal 類實現(xiàn)了 ipincipal 接口,這個接口有一個方法名叫做 isinrole(),它的參數(shù)是一個字符串,這個字符串就是要驗證的用戶角色。如果我們要顯示內(nèi)容給角色是 "administrator"的已登錄用戶,我們可以在 page_load 中添加下面代碼: 程序代碼

    if (user.isinrole("administrator"))
    adminlink.visible = true;

      整個的頁面代碼如下(為了簡便,把后臺代碼也寫在aspx頁面): 程序代碼

    <html>
    <head>
    <title>歡迎您!</title>
    <script runat="server">
    protected void page_load(object sender, eventargs e)
    {
    if (user.isinrole("administrator"))
    adminlink.visible = true;
    else
    adminlink.visible = false;
    }
    </script>
    </head>
    <body>
    <h2>歡迎!</h2>
    <p>歡迎來到阿木小屋 http://amuhouse.com/ ^_^</p>
    <asp:hyperlink id="adminlink" runat="server"
    text="管理首頁" navigateurl="./admin"/>
    </body>
    </html>

      樣,鏈接到 admin 目錄的hyperlink 控件只會顯示給角色是 administrator 的用戶。你也可以根據(jù)為未登錄用戶提供一個鏈接到登錄頁面,如:程序代碼

    protected void page_load(object sender, system.eventargs e)
    {

    if (user.isinrole("administrator"))
    {
    adminlink.text = "管理員請進";
    adminlink.navigateurl="./admin";
    }
    else if(user.isinrole("user"))
    {
    adminlink.text = "注冊用戶請進";
    adminlink.navigateurl="./user";

    }
    else
    {
    adminlink.text = "請登錄";
    adminlink.navigateurl="login.aspx?returnurl=" + request.path;
    }

    }

      這里,我們通過設(shè)置叫做returnurl的 querystring 變量,可以使用戶登錄成功后返回到當(dāng)前的這個頁面.

      小結(jié):

      本文用于幫助你理解基于角色安全機制的重要性、實用性,并且也用 asp.net 實現(xiàn)了基于角色的安全機制。它并不是一個很難實現(xiàn)的機制,不過它可能需要一些相關(guān)知識如 什么是用戶憑證,如何認證用戶身份,以及如何審定授權(quán)用戶。如果你覺得它很有幫助,我會非常高興。我希望它可以引導(dǎo)你在你的網(wǎng)站中去實現(xiàn)基于角色的窗體安全認證機制。

    發(fā)表評論 共有條評論
    用戶名: 密碼:
    驗證碼: 匿名發(fā)表
    主站蜘蛛池模板: 乐陵市| 新乐市| 炎陵县| 咸阳市| 凭祥市| 龙门县| 潼关县| 和顺县| 井研县| 上犹县| 宜宾县| 义乌市| 咸宁市| 永兴县| 高陵县| 乐亭县| 罗城| 塘沽区| 且末县| 景洪市| 商城县| 铜陵市| 建水县| 潞城市| 吉安市| 老河口市| 武夷山市| 洱源县| 金阳县| 武山县| 茌平县| 上杭县| 五指山市| 额尔古纳市| 石柱| 金堂县| 杭州市| 若羌县| 辉南县| 武汉市| 桂平市|