澳门蒲京网址【转】权限管理上 一、ASP.NET Forms身份证明。【转】权限管理上 一、ASP.NET Forms身份证明。

那么接下来我们就来分析下用户身份认证,那么接下来我们就来分析下用户身份认证

【转】权限管理上 一、ASP.NET
Forms身份验证

【转】权限管理上 一、ASP.NET
Forms身份证明

征:本文示例使用的VS2017跟MVC5。
系统无论大小、牛逼或屌丝,一般还离不上马注册、登录。那么连下去我们就算来分析下用户位置认证。

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

简而言之实现登录、注销

先在学习.net的时不懂得呀Forms身份证明,直接用session实现登录,效果呢甚好嘛。而且用户信息留存服务端,安全。
前端代码:

@if (string.IsNullOrWhiteSpace(ViewBag.UserName))
{
    <form action="/home/login1">
        <input type="text" name="userName" />
        <input type="submit" value="登录" />
    </form>
}
else
{
    <form action="/home/logout1">
        <div>当前用户已登录,登录名:@ViewBag.UserName</div>
        <input type="submit" value="退出" />
    </form>
}

后台代码:

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服务以及数据库的情事)。既然微软起一样模拟成熟之权杖管理我们怎么不要也?

简单实现登录、注销

此前以学习.net的时刻不掌握呀Forms身份证明,直接用session实现登录,效果呢非常好嘛。而且用户信息在服务端,安全。
前者代码:

@if (string.IsNullOrWhiteSpace(ViewBag.UserName))
{
    <form action="/home/login1">
        <input type="text" name="userName" />
        <input type="submit" value="登录" />
    </form>
}
else
{
    <form action="/home/logout1">
        <div>当前用户已登录,登录名:@ViewBag.UserName</div>
        <input type="submit" value="退出" />
    </form>
}

后台代码:

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服务和数据库的状况)。既然微软来一致效成熟的权杖管理我们为什么不用为?

Forms认证登录、注销

第一以web.config里开Forms身份验证:

<system.web>
  <authentication mode="Forms"></authentication>

后台代码:

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)
{
    <form action="/home/login2">
        <input type="text" name="userName" />
        <input type="submit" value="登录" />
    </form>
}
else
{
    <form action="/home/logout2">
        <div>当前用户已登录,登录名:@Context.User.Identity.Name</div>
        <input type="submit" value="退出" />
    </form>
}

这样几句子代码就贯彻了俺们的报到以及收回。和我们好因此session管理登录不同。Forms身份证明是一直将信存cookie到浏览器的。通过SetAuthCookie这个办法名吧可以拘留下。不过Cookie信息透过了加密。
这里产生必不可少说明session和cookie的涉。当我们运用session来保障用户状态的早晚,其实也利用了cookie。
澳门蒲京网址 1
只是Forms身份证明仅仅只是把信息存了cookie,而无于服务端维护一个遥相呼应之session。
无信仰而得测试。可以据此简单种植艺术还登录,然后去掉session就好测量出来了。(怎么清session?重开iis,或者涂改下后台代码在还编译访问)
【说明】用户征为什么而存cookie?因为HTTP是一个不论是状态的协商。对于服务器来说,每次要都是相同的。所以,只能通过每次要带的cookie来鉴别用户了。(暂时无考虑其他方)

Forms认证登录、注销

第一在web.config里开启Forms身份认证:

<system.web>
  <authentication mode="Forms"></authentication>

后台代码:

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)
{
    <form action="/home/login2">
        <input type="text" name="userName" />
        <input type="submit" value="登录" />
    </form>
}
else
{
    <form action="/home/logout2">
        <div>当前用户已登录,登录名:@Context.User.Identity.Name</div>
        <input type="submit" value="退出" />
    </form>
}

这么几句子代码就贯彻了俺们的登录和取消。和我们温馨之所以session管理登录不同。Forms身份验证是直拿消息存cookie到浏览器的。通过SetAuthCookie这个点子名吧得以看出来。不过Cookie信息通过了加密。
这边产生必要说明session和cookie的涉。当我们运用session来维持用户状态的早晚,其实也动了cookie。
澳门蒲京网址 2
不过Forms身份证明仅仅只是把消息存了cookie,而没以服务端维护一个相应的session。
匪信仰而得测试。可以就此简单种植方法都登录,然后去掉session就好测量出来了。(怎么清session?重开iis,或者修改下后台代码在重新编译访问)
【说明】用户征为什么而存cookie?因为HTTP是一个不论是状态的磋商。对于服务器来说,每次要都是一致的。所以,只能通过每次要带的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 && userData != null)
            // 4. 构造我们的MyFormsPrincipal实例,重新给context.User赋值。
            HttpContext.Current.User = new MyFormsPrincipal<UserInfo>(ticket, userData);
    }
    catch { /* 有异常也不要抛出,防止攻击者试探。 */ }
}

前者代码:

@{
    MyFormsPrincipal<UserInfo> user = Context.User as MyFormsPrincipal<UserInfo>;
    if (user == null)
    {
        <form action="/home/login3">
            <input type="text" name="userName" />
            <input type="submit" value="登录" />
        </form>
    }
    else
    {

        <form action="/home/logout2">
            <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<UserInfo>(ticket, userData);
MyFormsPrincipal需要贯彻接口MyFormsPrincipal

public class MyFormsPrincipal<TUserData> : 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;
    }
}

反也远非呀特别,就是实例化的时节传出票据及打定义数据就是好了。

打定义之身价认证标识

方用的记名很粗略,但实质上情形屡屡特别复杂。明显正常工作需要存的用户信息会使再多。那么我们是不是足以扩展身份标识为?答案是大势所趋的。
后台代码:

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

前端代码:

@{
    MyFormsPrincipal<UserInfo> user = Context.User as MyFormsPrincipal<UserInfo>;
    if (user == null)
    {
        <form action="/home/login3">
            <input type="text" name="userName" />
            <input type="submit" value="登录" />
        </form>
    }
    else
    {

        <form action="/home/logout2">
            <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<UserInfo>(ticket, userData);
MyFormsPrincipal需要实现接口MyFormsPrincipal

public class MyFormsPrincipal<TUserData> : 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里面

<system.web>
  <authentication mode="Forms" >
    <forms loginUrl="/home/index"></forms>

这种简易的授权验证明显是不够的。很多下某些页面只有少数人才能够顾。比如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();
}

没错,就是这么简单。说了这样多,来张效果图吧:
澳门蒲京网址 3

 

推荐阅读:

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

 

授权

生矣登录一般都距不起来授权。微软的东西好就算哼当,一般都是百分之百成套的。

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

直吃Action添加一个Authorize特性就哼了,这口虽会见自行检查是不是登录。如果没有登录活动跳反至登录页面。登录页面的安装或在web.config里面

<system.web>
  <authentication mode="Forms" >
    <forms loginUrl="/home/index"></forms>

这种简单的授权验证明显是不够的。很多辰光某些页面只有某些人才能够访问。比如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();
}

科学,就是这么简单。说了如此多,来张效果图吧:
澳门蒲京网址 4

 

推介阅读:澳门蒲京网址

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