ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Form表单认证

2021-06-09 14:34:32  阅读:378  来源: 互联网

标签:HTTP 请求 Form System 认证 登录 httpContext 表单 public


一、概述

1、理解Http的无状态特性

HTTP是一个无状态的协议,WEB服务器在处理所有传入HTTP请求时,根本就不知道某个请求是否是一个用户的第一次请求与后续请求,或者是另一个用户的请求。 WEB服务器每次在处理请求时,都会按照用户所访问的资源所对应的处理代码,从头到尾执行一遍,然后输出响应内容,WEB服务器根本不会记住已处理了哪些用户的请求,因此,我们通常说HTTP协议是无状态的。

2、为什么需要认证

虽然HTTP协议与WEB服务器是无状态,但我们的业务需求却要求有状态,典型的就是用户登录, 在这种业务需求中,要求WEB服务器端能区分某个请求是不是一个已登录用户发起的,或者当前请求是哪个用户发出的。 在开发WEB应用程序时,我们通常会使用Cookie来保存一些简单的数据供服务端维持必要的状态。

二、Form表单认证

登录的操作通常会检查用户提供的用户名和密码,因此登录状态也必须具有足够高的安全性。 在Forms身份认证中,由于登录状态是保存在Cookie中,而Cookie又会保存到客户端,因此,为了保证登录状态不被恶意用户伪造, ASP.NET采用了加密的方式保存登录状态。 为了实现安全性,ASP.NET采用【Forms身份验证凭据】(即FormsAuthenticationTicket对象)来表示一个Forms登录用户, 加密与解密由FormsAuthentication的Encrypt与Decrypt的方法来实现。

下面通过一张图详细的了解Form表单认证的过程:

 

 

三、Form表单认证的示例

1、创建mvc项目

 

 

2、mvc项目结构

 

 

3、Action加入认证

 HomeController中默认提供了几个action,我们加入[Authorize]标识,如下:

using System.Web.Mvc;

namespace FormAuthentication.Controllers
{
    public class HomeController : Controller
    {
        [Authorize]
        public ActionResult Index()
        {
            return View();
        }
        [Authorize]
        public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";

            return View();
        }
        [Authorize]
        public ActionResult Contact()
        {
            ViewBag.Message = "Your contact page.";

            return View();
        }
    }
}

因为路由默认启动Home/Index,所以启动下项目,看下效果:

 

 

提示没有授权请求home/index。Authorize做了什么,为什么加入[Authorize],action就无权访问了?我们先来分析下Authorize的定义:

namespace System.Web.Mvc
{
    //
    // 摘要:
    //     指定对控制器或操作方法的访问只限于满足授权要求的用户。
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
    public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
    {
        //
        // 摘要:
        //     初始化 System.Web.Mvc.AuthorizeAttribute 类的新实例。
        public AuthorizeAttribute();

        //
        // 摘要:
        //     获取或设置有权访问控制器或操作方法的用户角色。
        //
        // 返回结果:
        //     有权访问控制器或操作方法的用户角色。
        public string Roles { get; set; }
        //
        // 摘要:
        //     获取此特性的唯一标识符。
        //
        // 返回结果:
        //     此特性的唯一标识符。
        public override object TypeId { get; }
        //
        // 摘要:
        //     获取或设置有权访问控制器或操作方法的用户。
        //
        // 返回结果:
        //     有权访问控制器或操作方法的用户。
        public string Users { get; set; }

        //
        // 摘要:
        //     在过程请求授权时调用。
        //
        // 参数:
        //   filterContext:
        //     筛选器上下文,它封装有关使用 System.Web.Mvc.AuthorizeAttribute 的信息。
        //
        // 异常:
        //   T:System.ArgumentNullException:
        //     filterContext 参数为 null。
        public virtual void OnAuthorization(AuthorizationContext filterContext);
        //
        // 摘要:
        //     重写时,提供一个入口点用于进行自定义授权检查。
        //
        // 参数:
        //   httpContext:
        //     HTTP 上下文,它封装有关单个 HTTP 请求的所有 HTTP 特定的信息。
        //
        // 返回结果:
        //     如果用户已经过授权,则为 true;否则为 false。
        //
        // 异常:
        //   T:System.ArgumentNullException:
        //     httpContext 参数为 null。
        protected virtual bool AuthorizeCore(HttpContextBase httpContext);
        //
        // 摘要:
        //     处理未能授权的 HTTP 请求。
        //
        // 参数:
        //   filterContext:
        //     封装有关使用 System.Web.Mvc.AuthorizeAttribute 的信息。filterContext 对象包括控制器、HTTP 上下文、请求上下文、操作结果和路由数据。
        protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext);
        //
        // 摘要:
        //     在缓存模块请求授权时调用。
        //
        // 参数:
        //   httpContext:
        //     HTTP 上下文,它封装有关单个 HTTP 请求的所有 HTTP 特定的信息。
        //
        // 返回结果:
        //     对验证状态的引用。
        //
        // 异常:
        //   T:System.ArgumentNullException:
        //     httpContext 参数为 null。
        protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext);
    }
}

可以看出Authorize是应用于类或者方法的特性,AuthorizeAttribute实现了IAuthorizationFilter接口和FilterAttribute抽象类,接口中的OnAuthorization(AuthorizationContext filterContext)方法是最终验证授权的逻辑(其中AuthorizationContext是继承了ControllerContext类),AuthorizeCore方法是最终OnAuthorization()方法调用的最终逻辑。

  • bool AuthorizeCore(HttpContextBase httpContext):授权验证的逻辑处理,返回true则是通过授权,返回false则不是。若验证不通过时,OnAuthorization方法内部会调用HandleUnauthorizedRequest
  • void HandleUnauthorizedRequest(AuthorizationContext filterContext):这个方法是处理授权失败的事情。

我们看下AuthorizeCore核心代码如下:

    protected virtual bool AuthorizeCore(HttpContextBase httpContext)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException("httpContext");
            }
 
            IPrincipal user = httpContext.User;
            if (!user.Identity.IsAuthenticated)
            {
                return false;
            }
 
            if (_usersSplit.Length > 0 && !_usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase))
            {
                return false;
            }
 
            if (_rolesSplit.Length > 0 && !_rolesSplit.Any(user.IsInRole))
            {
                return false;
            }
 
            return true;
        }

AuthorizeAttribute提供了四个虚方法,我们可以不使用默认的认证逻辑,可以根据自己的项目情况进行重写。想了解更多的过滤器特性可以看另一篇文章:MVC过滤器特性

现在了解了Authorize的原理,那么我们希望认证失败可以弹出登录(认证)页面,而不是401页面。下面先创建登录相关的页面。

4、新建LoginController

新建LoginController截图如下:

LoginController中代码如下:

  • 检查用户提交的登录名和密码是否正确。

  • 根据登录名创建一个FormsAuthenticationTicket对象。

  • 调用FormsAuthentication.Encrypt()加密。

  • 根据加密结果创建登录Cookie,并写入Response。在登录验证结束后,一般会产生重定向操作, 那么后面的每次请求将带上前面产生的加密Cookie,供服务器来验证每次请求的登录状态。

using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;

namespace FormAuthentication.Controllers
{
    public class LoginController : Controller
    {
        // GET: Login
        public ActionResult Index()
        {
            string returnUrl = Request["ReturnUrl"];
            if (Request.HttpMethod=="POST")
            {
                string userId = Request["userid"];
                string password = Request["password"];
                if (userId=="admin"&&password=="123")
                {
                    var ticket = new FormsAuthenticationTicket (
                        1,//version
                        userId,//name
                        DateTime.Now,//issueDate
                        DateTime.Now.AddMinutes(5),//expiration
                        true,//isPersistent 持久性保存在cookie中
                        "role1,role2,role3,role4",//userData 用户数据
                        "/"//cookiePath
                        );
                    var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket));
                    cookie.HttpOnly = true;
                    HttpContext.Response.Cookies.Add(cookie);
                    return Redirect(returnUrl);
                }
            }
            return View();
        }
    }
}

5、新建LoginController/Index视图

新建LoginController/Index视图,截图如下:

代码如下:

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>
<form method="post">
    <input type="text" name="userid" />
    <input type="password" name="password" />
    <input type="submit" value="认证" />
</form>

 

6、重定向登录页面 

上边通过4/5步完成了登录相关的页面,那么请求home/index如何重定向到登录页面呢?这一步可以通过配置文件进行处理,在<system.web>节点中加入如下信息:

<authentication mode="Forms">
    <forms loginUrl="~/Login/Index" timeout="2880"/>
</authentication>

 

我们在执行下项目,看下效果:

 

可以看到,请求home/index的时候,认证失败,会重定向login/index页面,我们输入admin和123,点击认证:

 

认证成功后,生成一个加密的ticket放到cookie中,并且重定向原来的地址home/index:

 

 可以看到认证成功了,刷新页面,再次请求home/index,请求头中会携带cookie中的ticket票据,当票据没有过期或者被删除的情况下,就不需要再次认证:

 

标签:HTTP,请求,Form,System,认证,登录,httpContext,表单,public
来源: https://www.cnblogs.com/qtiger/p/14866727.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有