如何基于ASP.NET成员资格提供程序为ASP.NET MVC2创建自定义成员资格?
发布于 2010-05-06 18:41:40
我已经创建了一个包含自定义成员资格提供程序的新项目,并覆盖了MembershipProvider
抽象类中的ValidateUser
方法:
public class MyMembershipProvider : MembershipProvider
{
public override bool ValidateUser(string username, string password)
{
// this is where you should validate your user credentials against your database.
// I've made an extra class so i can send more parameters
// (in this case it's the CurrentTerritoryID parameter which I used as
// one of the MyMembershipProvider class properties).
var oUserProvider = new MyUserProvider();
return oUserProvider.ValidateUser(username,password,CurrentTerritoryID);
}
}
然后,我通过添加一个引用并从我的web.config中指出它,将该提供者连接到我的ASP.NET MVC2项目:
<membership defaultProvider="MyMembershipProvider">
<providers>
<clear />
<add name="MyMembershipProvider"
applicationName="MyApp"
Description="My Membership Provider"
passwordFormat="Clear"
connectionStringName="MyMembershipConnection"
type="MyApp.MyMembershipProvider" />
</providers>
</membership>
我确实需要创建一个继承RoleProvider
抽象类并覆盖GetRolesForUser
方法的自定义类。ASP.NET MVC授权使用该方法找出将哪些角色分配给当前登录的用户,并确保允许该用户访问控制器操作。
以下是我们需要采取的步骤:
1)创建继承RoleProvider抽象类并覆盖GetRolesForUser方法的自定义类:
public override string[] GetRolesForUser(string username)
{
SpHelper db = new SpHelper();
DataTable roleNames = null;
try
{
// get roles for this user from DB...
roleNames = db.ExecuteDataset(ConnectionManager.ConStr,
"sp_GetUserRoles",
new MySqlParameter("_userName", username)).Tables[0];
}
catch (Exception ex)
{
throw ex;
}
string[] roles = new string[roleNames.Rows.Count];
int counter = 0;
foreach (DataRow row in roleNames.Rows)
{
roles[counter] = row["Role_Name"].ToString();
counter++;
}
return roles;
}
2)通过我们的web.config将角色提供者与ASP.NET MVC2应用程序连接起来:
<system.web>
...
<roleManager enabled="true" defaultProvider="MyRoleProvider">
<providers>
<clear />
<add name="MyRoleProvider"
applicationName="MyApp"
type="MyApp.MyRoleProvider"
connectionStringName="MyMembershipConnection" />
</providers>
</roleManager>
...
</system.web>
3)将Authorize(Roles="xxx,yyy")设置在想要的控制器/操作之上:
[Authorization(Roles = "Customer Manager,Content Editor")]
public class MyController : Controller
{
......
}
就这样!现在它起作用了!
4)可选:设置自定义Authorize
属性,以便我们可以将不需要的角色重定向到AccessDenied页:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class MyAuthorizationAttribute : AuthorizeAttribute
{
/// <summary>
/// The name of the master page or view to use when rendering the view on authorization failure. Default
/// is null, indicating to use the master page of the specified view.
/// </summary>
public virtual string MasterName { get; set; }
/// <summary>
/// The name of the view to render on authorization failure. Default is "Error".
/// </summary>
public virtual string ViewName { get; set; }
public MyAuthorizationAttribute ()
: base()
{
this.ViewName = "Error";
}
protected void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus)
{
validationStatus = OnCacheAuthorization(new HttpContextWrapper(context));
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (AuthorizeCore(filterContext.HttpContext))
{
SetCachePolicy(filterContext);
}
else if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
// auth failed, redirect to login page
filterContext.Result = new HttpUnauthorizedResult();
}
else if (filterContext.HttpContext.User.IsInRole("SuperUser"))
{
// is authenticated and is in the SuperUser role
SetCachePolicy(filterContext);
}
else
{
ViewDataDictionary viewData = new ViewDataDictionary();
viewData.Add("Message", "You do not have sufficient privileges for this operation.");
filterContext.Result = new ViewResult { MasterName = this.MasterName, ViewName = this.ViewName, ViewData = viewData };
}
}
protected void SetCachePolicy(AuthorizationContext filterContext)
{
// ** IMPORTANT **
// Since we're performing authorization at the action level, the authorization code runs
// after the output caching module. In the worst case this could allow an authorized user
// to cause the page to be cached, then an unauthorized user would later be served the
// cached page. We work around this by telling proxies not to cache the sensitive page,
// then we hook our custom authorization code into the caching mechanism so that we have
// the final say on whether a page should be served from the cache.
HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
cachePolicy.SetProxyMaxAge(new TimeSpan(0));
cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);
}
}
现在,我们可以使用自己的made属性将用户重定向到访问拒绝视图:
[MyAuthorization(Roles = "Portal Manager,Content Editor", ViewName = "AccessDenied")]
public class DropboxController : Controller
{
.......
}
就这样!超级高手!
以下是我用来获取所有这些信息的一些链接:
我希望这些信息能有所帮助!
发布于 2010-05-05 14:47:17
发布于 2010-05-28 06:10:17
也可以用更少的代码来使用这种方法,我不完全确定这种方法是否同样安全,但对于您使用的任何数据库都能很好地工作。
在global.asax中
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;
// Get the stored user-data, in this case, our roles
string userData = ticket.UserData;
string[] roles = userData.Split(',');
HttpContext.Current.User = new GenericPrincipal(id, roles);
}
}
}
}
这样做的目的是从由FormsAuthenticationTicket生成的authCookie中读取角色
登录逻辑如下所示
public class dbService
{
private databaseDataContext db = new databaseDataContext();
public IQueryable<vwPostsInfo> AllPostsAndDetails()
{
return db.vwPostsInfos;
}
public IQueryable<role> GetUserRoles(int userID)
{
return (from r in db.roles
join ur in db.UsersRoles on r.rolesID equals ur.rolesID
where ur.userID == userID
select r);
}
public IEnumerable<user> GetUserId(string userName)
{
return db.users.Where(u => u.username.ToLower() == userName.ToLower());
}
public bool logOn(string username, string password)
{
try
{
var userID = GetUserId(username);
var rolesIQueryable = GetUserRoles(Convert.ToInt32(userID.Select(x => x.userID).Single()));
string roles = "";
foreach (var role in rolesIQueryable)
{
roles += role.rolesName + ",";
}
roles.Substring(0, roles.Length - 2);
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1, // Ticket version
username, // Username associated with ticket
DateTime.Now, // Date/time issued
DateTime.Now.AddMinutes(30), // Date/time to expire
true, // "true" for a persistent user cookie
roles, // User-data, in this case the roles
FormsAuthentication.FormsCookiePath);// Path cookie valid for
// Encrypt the cookie using the machine key for secure transport
string hash = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(
FormsAuthentication.FormsCookieName, // Name of auth cookie
hash); // Hashed ticket
// Set the cookie's expiration time to the tickets expiration time
if (ticket.IsPersistent) cookie.Expires = ticket.Expiration;
// Add the cookie to the list for outgoing response
HttpContext.Current.Response.Cookies.Add(cookie);
return true;
}
catch
{
return (false);
}
}
}
我使用两个表table: Role和table: UsersRoles将角色存储在数据库中,table:Role具有列: roleID和roleName,table:Role具有列: userID和roleID,这使得可以为多个用户提供多个角色,并且可以很容易地创建自己的逻辑来添加/删除用户的角色,等等。例如,这使您能够使用Authorize(Roles=“超级管理员”)。希望这能有所帮助。
edit:忘记进行密码检查,但是您只需在logOn方法中添加一个if,该方法检查所提供的用户名和密码是否进行了检查,如果没有,则返回false
https://stackoverflow.com/questions/2771094
复制相似问题