我正在开发一个内部网Web应用程序(asp.net和C#),现在我已经到达了安全和访问控制的里程碑。
该应用有:
现在,我通过应用程序使用的数据库上的“用户”表(FORMS AUTHENTICATION)使登录系统工作,然而在搜索了相当长的一段时间后,我不知道如何实现角色以限制访问部门页面和隐藏菜单选项。
以下是VS Express for Web中的解决方案结构:
“用户”表格记录是这样的,正如您所看到的,詹姆斯是特殊的,可以访问多个页面:
我打算制定以下方案:
用户只能访问其部门页面
某些用户可以访问其他部门的网页
我知道我必须在网络配置上有这样的东西,但是如果我有表格认证怎么办呢?
<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);
}
答案 0 :(得分:0)
首先创建一个pagesByDepatment表和一个department表,如下所示:
您需要在所有页面的每个请求中授权用户,对我来说,可能是自定义用户主体对象的情况
例如:
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,我希望有帮助