<!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"Cambria Math"; panose-1:2 4 5 3 5 4 6 3 2 4; mso-font-charset:1; mso-generic-font-family:roman; mso-font-format:other; mso-font-pitch:variable; mso-font-signature:0 0 0 0 0 0;} @font-face {font-family:Calibri; panose-1:2 15 5 2 2 2 4 3 2 4; mso-font-charset:0; mso-generic-font-family:swiss; mso-font-pitch:variable; mso-font-signature:-1610611985 1073750139 0 0 159 0;} @font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-unhide:no; mso-style-qformat:yes; mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:宋体; mso-fareast-theme-font:minor-fareast; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-font-kerning:1.0pt;} .MsoChpDefault {mso-style-type:export-only; mso-default-props:yes; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:595.3pt 841.9pt; margin:36.0pt 36.0pt 36.0pt 36.0pt; mso-header-margin:42.55pt; mso-footer-margin:49.6pt; mso-paper-source:0; layout-grid:15.6pt;} div.Section1 {page:Section1;} -->
asp.net portal starter kit 是采用的 “ 基于窗体的身份验证 ” 的身份验证模式。 forms 身份验证通常指这样一个系统,在该系统中使用 http 客户端重定向将未经身份验证的请求重定向到 html 窗体。如果应用程式需要在登录时通过 html 窗体收集自己的用户凭据,那么选择 forms 身份验证就非常好。用户提供凭据并提交该窗体。如果应用程式对请求进行身份验证,系统会发出一个 cookie ,在其中包含用于重新获取标识的凭据或密钥。随后发出在请求头中具有该 cookie 的请求。 asp.net 事件处理程式使用应用程式指定的所有验证方法对这些请求进行身份验证和授权。
数据库设计:
在 asp.net portal starter kit 中存储用户角色相关的表有三个:用户信息表( portal_users ),角色信息表( portal_roles ),用户角色关系表 ( portal_userroles )。通过用户角色关系表将用户信息和角色信息管理起来,可实现一个用户可有多种角色,一个角色也能同时是多个用户。三 表之间的关系如下:
程式实现:
在 asp.net portal starter kit 中用户登录成功后以 email 为用户标识名称建立用户标识时同时触发 global.asax.cs 中的 application_authenticaterequest 事件,将登录用户的角色信息读入 context.user 中。在 desktopdefault.aspx 根据 portalsettings.activetab.authorizedroles (当前活动标签的可访问 属性)判断是否可访问该标签的内容。如果可访问则呈现该标签下的用户模块,不能访问就重定向到访问错误页( accessdenied.aspx )。在管理 用户是否可编辑用户模块信息时,是判断用户角色是否在模块指定的可编辑角色(模块的 iseditable 属性)中。
关键代码:
1 、 根据用户的 email 获取用户的角色(以 string[] 的形式返回,一项表示一个角色,一个用户可有多个角色)( security.cs 中)
public string[] getroles(string email)
{
// 访问数据库的几步曲
sqlconnection myconnection = new sqlconnection(configurationsettings.appsettings["connectionstring"]);
sqlcommand mycommand = new sqlcommand("portal_getrolesbyuser", myconnection);
mycommand.commandtype = commandtype.storedprocedure;
sqlparameter parameteremail = new sqlparameter("@email", sqldbtype.nvarchar, 100);
parameteremail.value = email;
mycommand.parameters.add(parameteremail);
// 打开链接用 sqldatareader 执行查询
sqldatareader dr;
myconnection.open();
dr = mycommand.executereader(commandbehavior.closeconnection);
// 读取用户的角色信息
arraylist userroles = new arraylist();
while (dr.read()) {
userroles.add(dr["rolename"]);
}
dr.close();
return (string[]) userroles.toarray(typeof(string));
}
2 、 检查当前角色是否在指定的角色中( security.cs 中)
public static bool isinroles(string roles)
{
httpcontext context = httpcontext.current;
foreach (string role in roles.split( new char[] {;} ))
{
// 指定角色中有 all users 的也表示通过
if (role != "" && role != null && ((role == "all users") || (context.user.isinrole(role))))
{
return true;
}
}
return false;
}
3 、登录验证代码( signin.ascx.cs 中)
private void signinbtn_click(object sender, system.web.ui.imageclickeventargs e)
{
// 通过 usersdb 类尝试并验证用户是否合法
usersdb accountsystem = new usersdb();
string userid = accountsystem.login(email.text, portalsecurity.encrypt(password.text));
if ((userid != null) && (userid != ""))
{
// 为给定的 username 和 createpersistentcookie 创建身份验证票,并将其附加到 cookie 的传出响应的集合。他不执行重定向。
// 以 email 为用户标识名称建立用户标识时同时触发 global.asax.cs 中的 application_authenticaterequest 事件
formsauthentication.setauthcookie(email.text, remembercheckbox.checked);
// 从定向到起始页
response.redirect(request.applicationpath);
}
else
{
message.text = "<" + "br" + "> 登录失败! " + "<" + "br" + ">";
}
}
4 、 global.asax.cs 中的 application_authenticaterequest 事件
protected void application_authenticaterequest(object sender, eventargs e)
{
if (request.isauthenticated == true)
{
string[] roles;
// 将用户角色信息存入到 cookie
if ((request.cookies["portalroles"] == null) || (request.cookies["portalroles"].value == ""))
{
// 当 cookies 中没有时,从数据库中读取
usersdb user = new usersdb();
roles = user.getroles(user.identity.name);
// 以字符串的形式存储用户角色信息用 ";" 分隔,一个用户的多个角色
string rolestr = "";
foreach (string role in roles)
{
rolestr += role;
rolestr += ";";
}
// 创建身份角色验证的凭据
formsauthenticationticket ticket = new formsauthenticationticket(
1, // version 版本
context.user.identity.name, // user name cookie 名
datetime.now, // issue time 发布日期
datetime.now.addhours(1), // expires every hour 过期日期
false, // dont persist cookie 持久性 (false)
rolestr // roles 用户定义的数据初始化 (";" 分隔的角色字符串 )
);
// 加密凭证
string cookiestr = formsauthentication.encrypt(ticket);
// 将存有用户角色信息的字符串存入 cookie
response.cookies["portalroles"].value = cookiestr;
response.cookies["portalroles"].path = "/";
response.cookies["portalroles"].expires = datetime.now.addminutes(1);
}
else
{
// 当 cookies 中没有时,从 cookies 中读取
formsauthenticationticket ticket = formsauthentication.decrypt(context.request.cookies["portalroles"].value);
arraylist userroles = new arraylist();
foreach (string role in ticket.userdata.split( new char[] {;} ))
{
userroles.add(role);
}
roles = (string[]) userroles.toarray(typeof(string));
}
// 从 genericidentity 和角色名称数组( genericidentity 表示的用户属于该数组)初始化 genericprincipal 类的新实例。
context.user = new genericprincipal(context.user.identity, roles);
}
}
5 、 desktopdefault.aspx 中的判断是否可访问该页的代码
// 当前用户的角色不在当前活动标签的可访问角色中时,重定向到访问错误页
if (portalsecurity.isinroles(portalsettings.activetab.authorizedroles) == false)
{
response.redirect("~/admin/accessdenied.aspx");
}
6 、用户是否可编辑用户模块的代码
public static bool haseditpermissions(int moduleid)
{
string accessroles;
string editroles;
// 获取站点的设置信息
siteconfiguration sitesettings = (siteconfiguration) httpcontext.current.items["sitesettings"];
// 在设置信息中找到指定模块的行( xml 中的用户模块表 module )
siteconfiguration.modulerow modulerow = sitesettings.module.findbymoduleid(moduleid);
// 可编辑指定模块的角色信息
editroles = modulerow.editroles;
// 可访问模块所属标签的角色信息
accessroles = modulerow.tabrow.accessroles;
// 既有模块的编辑权,又有模块所属标签的访问权的才可修改指定模块
if(portalsecurity.isinroles(accessroles) == false || portalsecurity.isinroles(editroles) == false)
return false;
else
return true;
}