引言

大家都知道Http是无状态的协议,所以访问一个url,你并不能知道用户在之前是否已经登陆过。但是许多业务上的逻辑又离不开user的信息,这个时候就可以借助身份认证来记录当前user的登录状态。这其中Forms身份认证是最常见的身份认证。

这篇博客讲的内容就是结合一个最普通的MVC工程来讲解下Forms身份认证是怎么实现记录用户登录状态的。并说下怎么自定义一个身份认证。

Forms身份认证

打开Visual Studio 2013,新建Asp.net web mvc application,选择Internet Application

建好之后,按F5就能看到新建的网站。

修改Index,cshtml:

@if (Request.IsAuthenticated)
{
<text>用户已登录:</text>
@Context.User.Identity.Name
}
else
{
<text>用户未登录</text>
}

运行之后,你能看到:

继续修改Index.cshtml

@if (Request.IsAuthenticated)
{
<text>用户已登录:</text>
@Context.User.Identity.Name
}
else
{
<text>用户未登录</text>
<form method="post" action="@Request.RawUrl">
<input type="text" name="userName" />
<input type="submit" value="Submit" />
</form>
}

在对应的HomeController里加上对应的方法:

 [HttpPost]
public ActionResult Index(string id)
{
string userName = Request.Params["userName"];
FormsAuthentication.SetAuthCookie(userName, true);
return Index();
}

按F5运行之后,在输入框内填上user name,运行之后的结果:

注意上述的结果都是在web.config里开启Forms认证的基础上

<authentication mode="Forms">
</authentication>
内部运行机理

Forms身份认证的核心类是FormsAuthenticationModule

它是一个http module,实现了接口IHttpModule,这个接口的主要方法:

Init(HttpApplication Context)

看FomrsAuthenticationModule的实现

         public void Init(HttpApplication app)
{
if (!_fAuthChecked)
{
_fAuthRequired = AuthenticationConfig.Mode == AuthenticationMode.Forms;
_fAuthChecked = true;
}
if (_fAuthRequired)
{
FormsAuthentication.Initialize();
app.AuthenticateRequest += new EventHandler(this.OnEnter);
app.EndRequest += new EventHandler(this.OnLeave);
}
}

解释下代码,这个方法首先判断是否开启了Forms 认证,如果是Forms认证,就注册了两个HttpApplication管道事件AuthenticateRequest和EndRequest,继续看下

注册的AuthenticateRequest事件

 HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
this.OnAuthenticate(new FormsAuthenticationEventArgs(context));

找到了最核心的方法OnAuthenticate

由于此方法比较长,笔者只摘录出最核心的几句话

FormsAuthenticationTicket tOld = ExtractTicketFromCookie(e.Context, FormsAuthentication.FormsCookieName, out cookielessTicket);
e.Context.SetPrincipalNoDemand(new GenericPrincipal(new FormsIdentity(ticket), new string[]));

可以看出最核心的方法是Forms module从http context中的Cookie中解析出FormsAuthenticationTicket对象,然后new出来FormsIdentity,最后传给HttpContext

module一般都是注册Application管道事件,在事件里实现自己的核心处理,比如MVC,也是Module,实现自己的UrlRoutingModule,注册ResolveRequestCache事件

拓展:Authorization

Authorization可以控制user对网站的访问权限,比如哪种user可以访问哪种资源

在上述的工程web.config里加上

    <authentication mode="Forms">
<forms loginUrl="~/Home/Index"/>
</authentication>
<authorization>
<deny users="?"/>
</authorization>

deny users="?"代表只有登录用户才可以访问网站

于此对应的还有allow users="*" 允许任何用户可以访问

此类功能是UrlAuthorizationModule 实现,在此不在赘述,实现方式和FormsAuthenticationModule方式大同小异。

自定义身份认证

在某些业务功能里,需要cookie记住的功能不仅仅是user name,比如remember me功能,这个时候就可以用自定义身份认证来实现。

至于实现方式,既然已经知道Forms身份认证怎么实现,完全可以比葫芦画瓢实现自己需要的认证

下面写一个简单的实例

首先仿照FormsAuthenticationModule,注册AuthenticateRequest事件

         protected void Application_AuthenticateRequest()
{
HttpContext context = HttpContext.Current;
if (!context.Request.RawUrl.Equals("/"))
{
HttpCookie cookie = context.Request.Cookies["CustomCookie"];
string[] strs = cookie.Value.Split('x');
bool rememberMe = Convert.ToInt32(strs[]) == ? true : false;
HttpContext.Current.User = new CustomPrincipal(new CustomIdentity(strs[], rememberMe));
}
}

标注:

context.Request.RawUrl.Equals("/") 此句是简单的将Index.cshtml作为登录页面,实际应用中当然需要修改下。

其中CustomPrincipal和CustomIdentity类的代码如下

     public class CustomPrincipal : IPrincipal
{
private IIdentity identity; public CustomPrincipal(IIdentity identity)
{
this.identity = identity;
} public IIdentity Identity
{
get { return identity; }
} public bool IsInRole(string role)
{
throw new NotImplementedException();
}
} public class CustomIdentity : IIdentity
{ private string name;
private bool rememberMe; public CustomIdentity(string name, bool rememberMe)
{
this.name = name;
this.rememberMe = rememberMe;
} public string AuthenticationType
{
get { return string.Empty; }
} public bool IsAuthenticated
{
get { return true; }
} public string Name
{
get { return name; }
}
}

Index.cshtml继续作为登录页面,对应的登录方法:

         [HttpPost]
public ActionResult Index(string id)
{
string userName = Request.Params["userName"];
HttpCookie cookie = new HttpCookie("CustomCookie");
cookie.Value = userName + "x" + .ToString();
cookie.Expires = DateTime.Now.AddHours();
System.Web.HttpContext.Current.Response.SetCookie(cookie);
return RedirectToAction("About");
}

About.cshtml作为判断是否登录的页面

 @if (Request.IsAuthenticated)
{
<text>用户已登录:</text>
@Context.User.Identity.Name
}
else
{
<text>用户未登录</text>
}

最后运行结果:

到此,整篇博客已结束,许多地方说的还是比较简单抽象,望理解。

Forms身份认证的更多相关文章

  1. 细说ASP.NET Forms身份认证

    阅读目录 开始 ASP.NET身份认证基础 ASP.NET身份认证过程 如何实现登录与注销 保护受限制的页面 登录页不能正常显示的问题 认识Forms身份认证 理解Forms身份认证 实现自定义的身份 ...

  2. 简单的ASP.NET Forms身份认证

    读了几篇牛人的此方面的文章,自己也动手做了一下,就想有必要总结一下.当然我的文章质量自然不能与人家相比,只是写给从没有接触过这个知识点的朋友. 网站的身份认证我以前只知道session,偶然发现一些牛 ...

  3. IE11下Forms身份认证无法保存Cookie的问题

    ASP.NET中使用Forms身份认证常见的做法如下: 1. 网站根目录下的Web.config添加authentication节点 <authentication mode="For ...

  4. [转]IE11下Forms身份认证无法保存Cookie的问题

    本文转自:http://www.cnblogs.com/jaxu/p/3698377.html ASP.NET中使用Forms身份认证常见的做法如下: 1. 网站根目录下的Web.config添加au ...

  5. IE11下ASP.NET Forms身份认证无法保存Cookie的问题

    IE11下ASP.NET Forms身份认证无法保存Cookie的问题 折腾了三四天,今天才找到资料,解决了. 以下会转贴,还没来得及深究,先放着,有空再学习下. ASP.NET中使用Forms身份认 ...

  6. 关于Asp.Net Forms身份认证

    Asp.Net管道式的构建个我们提供了通过IHttpMoudle来订阅管线事件来达到干预HTTP请求的目的,Asp.Net的身份认证正是通过此种方式来对请求来执行身份认证的,这篇文章仅仅谈论Forms ...

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

    说明:本文示例使用的VS2017和MVC5. 系统无论大小.牛逼或屌丝,一般都离不开注册.登录.那么接下来我们就来分析下用户身份认证. 简单实现登录.注销 以前在学习.net的时候不知道什么Forms ...

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

    [转]权限管理学习 一.ASP.NET Forms身份认证 说明:本文示例使用的VS2017和MVC5. 系统无论大小.牛逼或屌丝,一般都离不开注册.登录.那么接下来我们就来分析下用户身份认证. 简单 ...

  9. ASP.NET Forms身份认证详解

    ASP.NET身份认证基础 在开始今天的内容之前,我想有二个最基础的问题首先要明确: 1. 如何判断当前请求是一个已登录用户发起的? 2. 如何获取当前登录用户的登录名? 在标准的ASP.NET身份认 ...

随机推荐

  1. SOS 调试扩展 (SOS.dll)

    http://blog.csdn.net/cslie/article/details/2158780 SOS 调试扩展 (SOS.dll) 提供公共语言运行时(CLR)内部环境的有关信息,帮助你在Wi ...

  2. C#编程简短总结

    封装 field一般为private,定义的时候可以不赋值.不赋值的时候一般被构造函数初始化赋值,其值用来保存类实例的数据,可以被内部方法使用作为计算的数据来源.当需要继承类继承本类的时候,field ...

  3. Jquery EasyUi实战教程布局篇

    转自:http://www.kwstu.com/ArticleView/kwstu_20139413501290 送给大家一个非常好的后台布局模板,本人后来就选择了这个模板http://www.kws ...

  4. [Ruby01]Class, Module, Object,Kernel的关系

    puts Class.ancestorsputs '11111111111111111111'puts Module.ancestorsputs '2222222222222222222'puts O ...

  5. ECSHOP数据表结构完整仔细说明教程

    From:http://www.ecshop119.com/ecshopjc-868.html s_account_log //用户账目日志表 字段 类型 Null 默认 注释 log_id medi ...

  6. 配置Windows Update,补丁更新

    配置Windows Update更新下载及安装方式: #NotificationLevel说明: # 0:未配置,不会对当前设置进行更改 # 1:从不检查更新 # 2:检查更新,但是让我选择是否下载和 ...

  7. Codeforces Gym 100286G Giant Screen 水题

    Problem G.Giant ScreenTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/con ...

  8. Android无法生成R文件的终极解决办法

    R文件如果在clean项目(Project—>Clean)和 Fix Project Properties(如下图):   如果在第一步无法解决的的时候,那可能原因就是资源文件调用的错误,比如资 ...

  9. Java log code example

    Java log example Logrecord filter import java.util.logging.Filter; import java.util.logging.Level; i ...

  10. Android 滑动效果高级篇(八)—— 自定义控件

    自定义控件,较常用View.ViewGroup.Scroller三个类,其继承关系如下: 本示例自定义控件,实现一个Gallery效果,并添加了一个显示View个数和位置的bar条,效果图: 自定义控 ...