加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

权限管理学习 一、ASP.NET Forms身份认证

发布时间:2020-12-15 21:25:20 所属栏目:asp.Net 来源:网络整理
导读:说明:本文示例使用的VS2017和MVC5。系统无论大

说明:本文示例使用的VS2017和MVC5。 系统无论大小、牛逼或屌丝,一般都离不开注册、登录。那么接下来我们就来分析下用户身份认证。

以前在学习.net的时候不知道什么Forms身份认证,直接用session实现登录,效果也蛮好嘛。而且用户信息存在服务端,安全。 前端代码:

@if (string.IsNullOrWhiteSpace(ViewBag.UserName))
{
    
} else {
当前用户已登录,登录名:@ViewBag.UserName
}

后台代码:

public ActionResult Index()
{
    ViewBag.UserName = Session["userName"]?.ToString();           
    return View();
}       

public void Login1(string userName)
{
if (!string.IsNullOrWhiteSpace(userName)) //为了方便演示,就不做真的验证了
Session["userName"] = userName;
else
Session["userName"] = null;
Response.Redirect(Request.UrlReferrer.LocalPath);//重定向到原来页面
}

public void Logout1()
{
Session["userName"] = null;
Response.Redirect(Request.UrlReferrer.LocalPath);//重定向到原来页面
}

是不是,简单明了。想要自己扩展或是定制什么功能都非常好用。不过我们需要维护session。比如系统重新发布,或者iis被自动重启。就会出现session丢失的情况。也就是用户会莫名其妙提升需要重新登录。体验非常不好。(这里先不讨论session服务和数据库的情况)。既然微软有一套成熟的权限管理我们为什么不用呢?

首先在web.config里开启Forms身份认证:


  

后台代码:

public void Login2(string userName)
{
    if (!string.IsNullOrWhiteSpace(userName))  //为了方便演示,就不做真的验证了
        FormsAuthentication.SetAuthCookie(userName,true); //登录
    Response.Redirect(Request.UrlReferrer.LocalPath);//重定向到原来页面
}

public void Logout2()
{
FormsAuthentication.SignOut();//登出
Response.Redirect(Request.UrlReferrer.LocalPath);//重定向到原来页面
}

前台代码:

@if (!Request.IsAuthenticated)
{
    
} else {
当前用户已登录,登录名:@Context.User.Identity.Name
}

如此几句代码就实现了我们的登录和注销。和我们自己用session管理登录不同。Forms身份认证是直接把信息存cookie到浏览器的。通过SetAuthCookie这个方法名也可以看出来。不过Cookie信息经过了加密。 这里有必要说明session和cookie的关系。当我们利用session来维持用户状态的时候,其实也用到了cookie。

上面使用的登录很简单,但实际情况往往很复杂。明显正常业务需要存的用户信息会要更多。那么我们是否可以扩展身份标识呢?答案是肯定的。 后台代码:

public void Login3(string userName)
{
    if (!string.IsNullOrWhiteSpace(userName))  //为了方便演示,就不做真的验证了     
    {
        UserInfo user = new UserInfo()
        {
            Name = userName,LoginTime = DateTime.Now
        };
        //1、序列化要保存的用户信息
        var data = JsonConvert.SerializeObject(user);
    //2、创建一个FormsAuthenticationTicket,它包含登录名以及额外的用户数据。
    FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(2,userName,DateTime.Now,DateTime.Now.AddDays(1),true,data);

    //3、加密保存
    string cookieValue = FormsAuthentication.Encrypt(ticket);

    // 4. 根据加密结果创建登录Cookie
    HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName,cookieValue);
    cookie.HttpOnly = true;
    cookie.Secure = FormsAuthentication.RequireSSL;
    cookie.Domain = FormsAuthentication.CookieDomain;
    cookie.Path = FormsAuthentication.FormsCookiePath;

    // 5. 写登录Cookie
    Response.Cookies.Remove(cookie.Name);
    Response.Cookies.Add(cookie);
}
Response.Redirect(Request.UrlReferrer.LocalPath);//重定向到原来页面

}

然后在Global.asax的Application_AuthenticateRequest方法:

protected void Application_AuthenticateRequest()
{
    GetUserInfo();
}

//通过coolie解密 读取用户信息到 HttpContext.Current.User
public void GetUserInfo()
{
// 1. 读登录Cookie
HttpCookie cookie = Request.Cookies[FormsAuthentication.FormsCookieName];

try
{
    UserInfo userData = null;
    // 2. 解密Cookie值,获取FormsAuthenticationTicket对象
    FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);

    if (ticket != null && string.IsNullOrEmpty(ticket.UserData) == false)
        // 3. 还原用户数据
        userData = JsonConvert.DeserializeObject<UserInfo>(ticket.UserData);

    if (ticket != null &amp;&amp; userData != null)
        // 4. 构造我们的MyFormsPrincipal实例,重新给context.User赋值。
        HttpContext.Current.User = new MyFormsPrincipal<UserInfo>(ticket,userData);
}
catch { /* 有异常也不要抛出,防止攻击者试探。 */ }

}

前端代码:

@{
    MyFormsPrincipal user = Context.User as MyFormsPrincipal;
    if (user == null)
    {
        
} else {
    <form action="/home/logout2"&gt;
        <div>当前用户已登录,登录名:@Context.User.Identity.Name</div>
        <div>当前用户已登录,登录时间:@user.UserData.LoginTime</div>
        <input type="submit" value="退出" />
    </form>
}

}

其实整个过程和FormsAuthentication.SetAuthCookie(userName,true); //登录是等效的。只是我们通过扩展,存了我们想要存储的数据。 过程也比较简单:

  • 构造要存储的数据
  • 序列化
  • 把序列化信息放入FormsAuthenticationTicket对象
  • 通过FormsAuthentication.Encrypt加密对象
  • 发送cookie到浏览器

这里稍微复杂点的地方就是解密然后给User赋值HttpContext.Current.User = new MyFormsPrincipal(ticket,userData);。 MyFormsPrincipal需要实现接口MyFormsPrincipal

public class MyFormsPrincipal : IPrincipal where TUserData : class,new()
{
    private IIdentity _identity;
    private TUserData _userData;
public MyFormsPrincipal(FormsAuthenticationTicket ticket,TUserData userData)
{
    if (ticket == null)
        throw new ArgumentNullException("ticket");
    if (userData == null)
        throw new ArgumentNullException("userData");

    _identity = new FormsIdentity(ticket);
    _userData = userData;
}

public TUserData UserData
{
    get { return _userData; }
}

public IIdentity Identity
{
    get { return _identity; }
}

public bool IsInRole(string role)//这里暂时不实现
{
    return false;
}

}

倒也没有什么特别,就是实例化的时候传入票据和自定义数据就好了。

有了登录一般都离不开授权。微软的东西好就好在,一般都是成套成套的。

[Authorize]
public ActionResult LoginOk()
{
    return View();
}

直接给Action添加一个Authorize特性就好了,这人就会自动检查是否登录。如果没有登录自动跳转到登录页面。登录页面的设置还是在web.config里面


  
    

这种简单的授权验证明显是不够的。很多时候某些页面只有某些人才能访问。比如VIP。那么我们又要扩展了。

//继承 AuthorizeAttribute
public class MyAuthorizeAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.User.Identity.Name != "农码一生")
        {
            filterContext.HttpContext.Response.Write("您不是vip用户,不能访问机密数据");
            filterContext.HttpContext.Response.End();
            return;
        }
        base.OnAuthorization(filterContext);
    }
}
[MyAuthorize]
public ActionResult LoginVIP()
{
    return View();
}

是的,就是这么简单。说了这么多,来张效果图吧:

推荐阅读:

  • http://www.cnblogs.com/fish-li/archive/2012/04/15/2450571.htmlDemo:
  • https://github.com/zhaopeiym/BlogDemoCode/tree/master/权限管理/1-Forms身份认证

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读