基于列表的角色形成身份验证和隐藏菜单项

时间:2013-12-23 10:01:07

标签: c# asp.net forms-authentication roles

我正在开发一个内部网Web应用程序(asp.net和C#),现在我已经到达了安全和访问控制的里程碑。

该应用有:

  • Login.aspx页面(公司内部任何人都可以访问)
  • Home.aspx页面(仅在登录后访问)左侧有一个菜单,其中包含所有部门页面和一个不会触发的注销按钮
  • 多个部门页面

现在,我通过应用程序使用的数据库上的“用户”表(FORMS AUTHENTICATION)使登录系统工作,然而在搜索了相当长的一段时间后,我不知道如何实现角色以限制访问部门页面和隐藏菜单选项。

以下是VS Express for Web中的解决方案结构:

structure

“用户”表格记录是这样的,正如您所看到的,詹姆斯是特殊的,可以访问多个页面:

Users

我打算制定以下方案:

  • 用户只能访问其部门页面

  • 某些用户可以访问其他部门的网页

我知道我必须在网络配置上有这样的东西,但是如果我有表格认证怎么办呢?

<location path="Marketing.aspx">
<system.web>
    <authorization>
        <deny roles="AD\Grupo Planeamento"/>
        <allow roles="AD\Grupo Marketing"/>
    </authorization>
</system.web>

现在,在代码上,所有网页上的Page_Load事件都为空

母版页上的菜单

<div class="span4">
                <asp:ContentPlaceholder ID="menu_lateral" runat="server">
                    <ul class="nav nav-list">
                          <li class="nav-header">Departamentos</li>
                          <li><a href="Comercial.aspx" title="Comercial">Comercial</a></li>
                          <li><a href="Compras.aspx">Compras</a></li>
                          <li><a href="Contabilidade.aspx">Contabilidade</a></li>
                          <li><a href="Controloegestao.aspx">Controlo e Gestão</a></li>
                          <li><a href="Exportação.aspx">Exportação</a></li>
                          <li><a href="Manutenção.aspx">Manutenção</a></li>
                          <li><a href="Matérias Primas.aspx">Matérias Primas</a></li>
                          <li><a href="Mercado Nacional.aspx">Mercado Nacional</a></li>
                          <li><a href="Planeamento.aspx">Planeamento</a></li>
                          <li><a href="Qualidade.aspx">Qualidade</a></li>
                          <li><a href="Tesouraria.aspx">Tesouraria</a></li>
                    </ul>
                </asp:ContentPlaceholder>
            </div>

Webconfig

<system.web>
<authentication mode="Forms">
    <forms name="frmlogin" />
    <!—if i add “loginUrl="Login.aspx"” I can only login at the second page load/attempt, dunno why />-->
</authentication>
    <authorization>
        <deny users="?"/>
    </authorization>

的Login.aspx

<asp:Content ID="rightcontentdown" ContentPlaceHolderID="rightcontentdown" Runat="Server">
<form id="frmlogin" runat="server">
            <table class="logintable">
            <tr><th colspan="3" rowspan="1">Login</th>
            <tr><td>User:</td>
                <td colspan="2" rowspan="1"><input id="UserNameTextBox" type="text" runat="server"></td>
                <td colspan="2" rowspan="1"><asp:RequiredFieldValidator ID="vUserName" ControlToValidate="UserNameTextBox" Display="Static" ErrorMessage="Username Inválido" runat="server" /></td>

            <tr>
                <td>Password:</td>
                <td colspan="2" rowspan="1"><input id="PasswordTextBox" type="password" runat="server"></td>
                <td colspan="2" rowspan="1"><asp:RequiredFieldValidator ID="vUserPass" ControlToValidate="PasswordTextBox" Display="Static" ErrorMessage="Password Inválida" runat="server" /></td>

            <tr>
                <td><asp:Button ID="LoginButton" runat="server" Text="Login" onclick="LoginButton_Click" /><asp:CheckBox id="RemPassword" runat="server" autopostback="false" text="Lembrar-me"/></td>
            <tr>
                <td><asp:Label id="MsgLabel" runat="server" /></td>

        </table>
</form>

Login.aspx.cs

private bool ValidateUser(string userName, string password)
{
    SqlConnection conn;
    SqlCommand cmd;
    string pwd = null;

    //Checks for invalid userName
    //username must not be null
    if ((userName == null) || (userName.Length == 0))
    {
        return false;
    }

    //checks for invalid password, password should not be null
    if ((password == null) || (password.Length == 0))
    {
        return false;
    }

    try
    {
        //Creating connection to the sql server
        //Connection string is fetched from web.config file, see TestDb1ConnectionString there
        conn = new SqlConnection(GetConnectionString());
        conn.Open(); //Opening connection

        string sqlcmd = "Select PASSWORD from [Users] where NOME=@username";
        cmd = new SqlCommand(sqlcmd, conn);
        cmd.Parameters.Add("@username", System.Data.SqlDbType.VarChar).Value = userName;

        // Execute command and fetch password field into pwd string
        pwd = (string)cmd.ExecuteScalar();

        //Cleanup command and close connection
        cmd.Dispose();
        conn.Close();
        if (pwd == password)
            return true; // Validates the user and return true
        else
            return false;
    }
    catch (Exception ex)
    {
        // Add errer handling code here
        throw ex;
    }
}

protected void LoginButton_Click(object sender, EventArgs e)
{
    if (ValidateUser(UserNameTextBox.Value, PasswordTextBox.Value))
         {
                 FormsAuthenticationTicket tkt;
                 string cookiestr;
                 HttpCookie ck;
                 tkt = new FormsAuthenticationTicket(1, UserNameTextBox.Value, DateTime.Now, DateTime.Now.AddMinutes(30), RemPassword.Checked, "Custom Data");
                 cookiestr = FormsAuthentication.Encrypt(tkt);
                 ck = new HttpCookie(FormsAuthentication.FormsCookieName, cookiestr);
                 if (RemPassword.Checked)
                 ck.Expires = tkt.Expiration;
                 ck.Path = FormsAuthentication.FormsCookiePath;
                 Response.Cookies.Add(ck);

                 string strRedirect;
                 strRedirect = Request["ReturnUrl"];
                 if (strRedirect == null)
                 strRedirect = "Home.aspx";
                 Response.Redirect(strRedirect, true);
         }
                 else
                 Response.Redirect("Login.aspx", true);
}

Home.aspx

<asp:Content ID="rightcontentdown" ContentPlaceHolderID="rightcontentdown" Runat="Server">
    <asp:Button runat="server" Text="Terminar Sessão" ID="SignOutButton" OnClick="Signoutbutton_click" />
</asp:Content>

Home.aspx.cs

protected void Signoutbutton_click(object sender, EventArgs e)
{
    FormsAuthentication.SignOut();
    Session.Abandon();
    Session.Contents.RemoveAll();
    Response.Redirect("Login.aspx", true);
}

1 个答案:

答案 0 :(得分:0)

首先创建一个pagesByDepatment表和一个department表,如下所示:

    • Id(int)
    • 姓名(字符串)
  • PagesByDepartment
    • Id(int)
    • DepartmentId(int)
    • PageName(字符串)
  • 用户
    • Id(int)
    • 用户名(字符串)
    • 密码(字符串) - 如果您可以将其哈希到位数组中会更好:)
    • DepartmentId(int)

您需要在所有页面的每个请求中授权用户,对我来说,可能是自定义用户主体对象的情况

例如:

public class MyAppPrincipal :IPrincipal, IMyAppPrincipal
      {
            private IIdentity _identity;
            private string _department;
            public MyAppPrincipal( IIdentity identity, department)
            {
                  _identity = identity;
                  _department = department;
            }

            public bool IsPageEnabled(string pageName)
            {
                //DB is your access to your database, I know that you´re using plain ADO.NET here so put query here or cache the elements in your app_start and read them from it....
                //let´s say you have a method that you pass the pagename and the department
                 return DB.IsPageEnabled( pageName, this._department);

            }
        }

将部门添加到自定义用户数据中的身份验证票证

protected void LoginButton_Click(object sender, EventArgs e)
{
    if (ValidateUser(UserNameTextBox.Value, PasswordTextBox.Value))
         {
                 // get the department from your DB
                 string department = DB.GetDepartmentByUsername(UserNameTextBox.Value);

                 FormsAuthenticationTicket tkt;
                 string cookiestr;
                 HttpCookie ck;

                          tkt = new FormsAuthenticationTicket(2,  // version 
                          UserNameTextBox.Value, 
                          DateTime.Now, 
                          DateTime.Now.AddMinutes(30), 
                          RemPassword.Checked, 
                          department, // instead of custom data
                          FormsAuthentication.FormsCookiePath);

                 cookiestr = FormsAuthentication.Encrypt(tkt);
                 ck = new HttpCookie(FormsAuthentication.FormsCookieName, cookiestr);
                 if (RemPassword.Checked)
                 ck.Expires = tkt.Expiration;
                 ck.Path = FormsAuthentication.FormsCookiePath;
                 Response.Cookies.Add(ck);

                 string strRedirect;
                 strRedirect = Request["ReturnUrl"];
                 if (strRedirect == null)
                 strRedirect = "Home.aspx";
                 Response.Redirect(strRedirect, true);
         }
                 else
                 Response.Redirect("Login.aspx", true);
}

然后你需要一个httpmodule来验证/授权

public class CustomAuthenticationModule : IHttpModule 
      { 

            public void Init(HttpApplication httpApp) 
            { 
                  httpApp.AuthorizeRequest += new EventHandler(this.AuthorizaRequest); 
                  httpApp.AuthenticateRequest += new EventHandler(this.AuthenticateRequest); 
            } 
            public void Dispose() 
            {} 

            private void AuthorizaRequest( object sender, EventArgs e) 
            {     
                  if (HttpContext.Current.User != null) 
                  { 
                         if (HttpContext.Current.User.Identity.IsAuthenticated) 
                        { 
                              if (HttpContext.Current.User is MyAppPrincipal) 
                              { 

                              MyAppPrincipal principal = (MyAppPrincipal) HttpContext.Current.User; 
                              if (!principal.IsPageEnabled(HttpContext.Current.Request.Path) ) 
                                          HttpContext.Current.Server.Transfer( "unauthorized.aspx"); 
                              } 
                        } 
                  } 
            } 

            private void AuthenticateRequest(object sender, EventArgs e) 
            { 
                  if (HttpContext.Current.User != null) 
                  { 

                        if (HttpContext.Current.User.Identity.IsAuthenticated) 
                        { 
                              if (HttpContext.Current.User.Identity is FormsIdentity) 
                              { 
                                    var id = HttpContext.Current.User.Identity; 
                                    FormsAuthenticationTicket ticket = id.Ticket; 
                                    string cookieName = System.Web.Security.FormsAuthentication.FormsCookieName; 
                                    string userData = 
                                          System.Web.HttpContext.Current.Request.Cookies[cookieName].Value; 

                                    ticket  = FormsAuthentication.Decrypt(userData); 

                                    string department=""; 
                                    if( userData.Length > 0 ) 
                                          department= ticket.UserData; 
                                    HttpContext.Current.User = new 
                                    MyAppPrincipal(_identity, department);                          
                              } 
                        } 
                  } 
            }//AuthenticateRequest 
      } //class 
}

不要忘记添加自定义模块

<httpModules > 
      < add type ="myapp, SecurityModules" name ="CustomAuthenticationModule" /> 
</ httpModules > 

PD:你可以把它读作伪代码,因为我在文本框上编码而不是VS,我希望有帮助