.net MVC使用IPrincipal进行Form登录即权限验证(3)
.net mvc使用iprincipal进行form登录即权限验证,供大家参考,具体内容如下
1.在mvc项目中添加用户类,可以根据实际项目需求添加必要属性
public class userdata { /// <summary> /// id /// </summary> public int userid { get; set; } /// <summary> /// 用户名 /// </summary> public string username { get; set; } /// <summary> /// 角色id列表 /// </summary> public list<int> roles { get; set; } }
2.添加类principal实现iprincipal接口
public class principal : iprincipal { public iidentity identity { get; private set;} public userdata account { get; set; } /// <summary> /// 构造函数 /// </summary> /// <param name="ticket"></param> /// <param name="account"></param> public principal(formsauthenticationticket ticket, userdata account) { if (ticket == null) throw new argumentnullexception("ticket"); if (account == null) throw new argumentnullexception("userdata"); this.identity = new formsidentity(ticket); this.account = account; } public bool isinrole(string role) { if (string.isnullorempty(role)) return true; if (this.account == null || this.account.roles == null) return false; return role.split(',').any(q => account.roles.contains(int.parse(q))); } }
iprincipal接口有对象identity已经需要实现验证角色方法isinrole()。在我们的实现类中添加了"用户信息(userdata)"属性account。
构造函数中进行了初始化,第一个对象为form验证的票据对象,下面ticket会携带用户信息一起保存进cookie中。
3.创建存储cookie和读取cookie的类
/// <summary> /// 写入cookie和读取cookie /// </summary> public class httpformsauthentication { //将用户信息通过ticket加密保存到cookie public static void setauthenticationcoolie(userdata account, int rememberday = 0) { if (account == null) throw new argumentnullexception("account"); //序列化account对象 string accountjson = jsonconvert.serializeobject(account); //创建用户票据 var ticket = new formsauthenticationticket(1, account.username, datetime.now, datetime.now.adddays(rememberday), false, accountjson); //加密 string encryptaccount = formsauthentication.encrypt(ticket); //创建cookie var cookie = new httpcookie(formsauthentication.formscookiename, encryptaccount) { httponly = true, secure = formsauthentication.requiressl, domain = formsauthentication.cookiedomain, path = formsauthentication.formscookiepath }; if (rememberday > 0) cookie.expires = datetime.now.adddays(rememberday); //写入cookie httpcontext.current.response.cookies.remove(cookie.name); httpcontext.current.response.cookies.add(cookie); } //获取cookie并解析出用户信息 public static principal tryparseprincipal(httpcontext context) { if (context == null) throw new argumentnullexception("context"); httprequest request = context.request; httpcookie cookie = request.cookies[formsauthentication.formscookiename]; if (cookie == null || string.isnullorempty(cookie.value)) { return null; } //解密coolie值 formsauthenticationticket ticket = formsauthentication.decrypt(cookie.value); userdata account = jsonconvert.deserializeobject<userdata>(ticket.userdata); return new principal(ticket, account); } }
存储cookie时将用户信息序列化后的字符串accountjson由ticket其携带加密后保存入cookie中,具体的accountjson被赋值给formsauthenticationticket的userdata属性。
可看到解析时将ticket.userdata反序列化后得到了原始的用户信息对象,然后生成principal对象。
解析cookie得到principal对象的方法tryparseprincipal,下面会在发起请求时用到,而返回的principal对象被赋值给httpcontext.user。
4.在global.asax中注册application_postauthenticaterequest事件,保证权限验证前将cookie中的用户信息取出赋值给user
protected void application_postauthenticaterequest(object sender, system.eventargs e) { httpcontext.current.user = httpformsauthentication.tryparseprincipal(httpcontext.current); }
5.集成authorizeattribute特性类并重写authorizecore,handleunauthorizedrequest方法
public class formauthorizeattribute : authorizeattribute { /// <summary> /// 先进入此方法,此方法中会调用 authorizecore 验证逻辑,验证不通过会调用 handleunauthorizedrequest 方法 /// </summary> /// <param name="filtercontext"></param> public override void onauthorization(authorizationcontext filtercontext) { base.onauthorization(filtercontext); } /// <summary> /// 权限验证 /// </summary> /// <param name="httpcontext"></param> /// <returns></returns> protected override bool authorizecore(httpcontextbase httpcontext) { var user = httpcontext.user as principal; if (user != null) return user.isinrole(base.roles); return false; } protected override void handleunauthorizedrequest(authorizationcontext filtercontext) { //验证不通过,直接跳转到相应页面,注意:如果不是哟娜那个以下跳转,则会继续执行action方法 filtercontext.result = new redirectresult("~/login/index"); } }
authorizecore与handleunauthorizedrequest方法均是在方法onauthorization中调用,authorizecore验证不通过才会调用handleunauthorizedrequest方法。
将验证代码在authorizecore中实现,验证不通过的逻辑在handleunauthorizedrequest方法中实现。
6.添加logincontroller实现登录逻辑
namespace mvcauthorizetest.controllers { public class logincontroller : controller { [allowanonymous] // get: login public actionresult index(string returnurl) { viewbag.returnurl = returnurl; return view(); } [httppost] [allowanonymous] public actionresult index(string name, string password, bool rememberme, string returnurl) { var account = new userdata() { username = name, userid = 110, roles = new list<int>() { 1, 2, 3 } }; httpformsauthentication.setauthenticationcoolie(account, rememberme ? 7 : 0); if (url.islocalurl(returnurl) && returnurl.length > 1 && returnurl.startswith("/") && !returnurl.startswith("//") && !returnurl.startswith("/\\")) { return redirect(returnurl); } else { return redirecttoaction("index", "home"); } } // post: /account/logoff [httppost] public actionresult logoff() { system.web.security.formsauthentication.signout(); return redirecttoaction("index", "home"); } } }
7.对需要验证的controller或action添加特性标签
[formauthorize(roles = "1,2")] public class homecontroller : controller { [formauthorize] public actionresult index() { return view(); } }
如图
8.在添加filterconfig中添加全局注册filter,减少每个action分别设置。如果有不需要验证的页面,添加[allowanonymous]特性即可
public class filterconfig { public static void registerglobalfilters(globalfiltercollection filters) { filters.add(new handleerrorattribute()); //全局注册filter filters.add(new formauthorizeattribute()); } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: Dubbo之服务消费原理