权力文学习,Forms身份申明

by admin on 2019年4月7日

【转】权限法学习 1、ASP.NET
Forms身份验证

【转】权限经济学习 一、ASP.NET
Forms身份验证

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

注解:本文示例使用的VS20一柒和MVC伍。
系统无论大小、牛逼或屌丝,壹般都离不开注册、登录。那么接下去大家就来分析下用户身份证明。

粗略完结登录、注销

先前在学习.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);//重定向到原来页面
}

是还是不是,容易明了。想要自个儿扩充或是定制什么效劳都11分好用。可是大家须求爱惜session。比如系统再次宣布,也许iis被机关心尊敬启。就会冒出session丢失的场地。也正是用户会莫明其妙进步必要再度登录。体验10分倒霉。(那里先不商讨session服务和数据库的景色)。既然微软有1套成熟的权位管理大家为何不要啊?

简单来说完结登录、注销

先前在学习.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丢失的状态。也正是用户会不可捉摸升高必要重新登录。体验11分倒霉。(那里先不研商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是1个无状态的说道。对于服务器来说,每便请求都以1模壹样的。所以,只好通过每一趟请求带的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那些法子名也足以看出来。可是库克ie音讯透过了加密。
此地有须要表明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); //登录是千篇1律的。只是大家经过增加,存了大家想要存款和储蓄的数量。
进程也比较简单:

  • 组织要存款和储蓄的多少
  • 序列化
  • 把连串化新闻放入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

 

引入阅读:

 

授权

有了登录1般都离不开授权。微软的事物好就辛亏,一般都以全体成套的。

[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

 

推荐介绍阅读:

 

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图