最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来。

十年河东十年河西,莫欺少年穷

学无止境,精益求精

   最近在自学MVC,遇到的问题很多,索性一点点总结下。

[AllowAnonymous] 用于无需授权登录的控制器

正题:

做过三层架构的童鞋都知道,如果要验证/授权一个用户登录,我们一般采取如下方法:

1、用户输入用户名、密码进行登录

2、账户/密码正确,保存用户信息至Cookies或者Session,跳转至主页面

3、在主页面继承BasePage类,并在Page_Load的时候,判断Cookies或者Session的值,如果Cookies或者Session中存放的值在数据库验证成功,则可以观看主页面信息,如果验证不成功,或者Session/Cookies值为NULL时,直接执行语句:Response.Redirect(../Login.aspx);

上述方法很简单,功能上也实现了登录的认证与授权,相信很多人写的项目都会采取此方法进行判断,殊不知:这种方法安全系数较低,而且违背了NET的登录授权与验证原则。那么NET中的授权与验证又是什么呢?

.net中的认证(authentication)与授权(authorization)

   认证(authentication) 就是 :判断用户有没有登录,用户输入的账户密码等信息是否通过数据库比对

授权(authorization) 就是:用户登录后的身份/角色识别,用户通过认证后<登陆后>我们记录用户的信息并授权

.net中与"认证"对应的是IIdentity接口,而与"授权"对应的则是IPrincipal接口,这二个接口的定义均在命名空间System.Security.Principal中,详情如下:

用户认证接口:

using System;
using System.Runtime.InteropServices; namespace System.Security.Principal
{
[ComVisible(true)]
public interface IIdentity
{
string AuthenticationType { get; }
bool IsAuthenticated { get; }
string Name { get; }
}
}

用户授权接口:

using System;
using System.Runtime.InteropServices; namespace System.Security.Principal
{
[ComVisible(true)]
public interface IPrincipal
{
IIdentity Identity { get; }
bool IsInRole(string role);
}
}

应该注意到:IPrincipal接口中包含着一个只读的IIdentity

1、IIdentity 接口中属性的含义:

AuthenticationType  验证方式:NET中有Windows、Forms、Passport三种验证方式,其中以Forms验证用的最多,本节讲解的MVC验证与授权就是基于Form。

IsAuthenticated  是否通过验证,布尔值

Name  用户登录的账户名称

2、IPrincipal 接口中属性的含义:

IIdentity  上述IIdentity接口的实例

IsInRole  布尔值,验证用户权限

下面我们对HttpContext封闭类刨根问底

HttpContext.User本身就是一个IPrincipal接口的实例。

有了上面的预备知识,我们在程序中处理认证问题时,只需对HttpContext.User赋值即可。

下面是小弟模拟的一个授权方法

        /// <summary>
/// 模拟授权 此处不经过验证 直接授权访问 UserCenter()
/// </summary>
/// <returns></returns>
public ActionResult Login()
{
GenericIdentity _identity = new GenericIdentity("天才卧龙", "Forms");
GenericPrincipal _principal = new GenericPrincipal(_identity, new string[] { "admins", "vips" });
HttpContext.User = _principal;
return RedirectToAction("UserCenter");
} [Authorize(Roles = "admins")]
public ActionResult UserCenter()
{
return View();
}

上面的方法中,一旦运行登陆页,不需要填账户密码,直接会访问UserCenter(),即:直接会跳转到个人中心

好啦,如果上边的例子大家看懂了,那么下面的登录其实就很简单了,和上述所讲一样:由于 HttpContext.User 本身就是一个IPrincipal接口的实例!因此:我们只需给这个实例赋值即可,上面的例子就证实了这一点。

咱们回到开篇的描述,一般我们都是通过Session或者cookies就行Forms验证登录,那么在MVC中我们应当怎么做呢?

   1.MVC的Forms验证

Forms验证在内部的机制为把用户数据加密后保存在一个基于cookie的票据FormsAuthenticationTicket中,因为是经过特殊加密的,所以应该来说是比较安全的。而.net除了用这个票据存放自己的信息外,还留了一个地给用户自由支配,这就是现在要说的UserData。

UserData可以用来存储string类型的信息,并且也享受Forms验证提供的加密保护,当我们需要这些信息时,也可以通过简单的get方法得到,兼顾了安全性和易用性,用来保存一些必须的敏感信息还是很有用的。

在此,本案例中UserData用于存储用户角色值,admins/vips/superadmins等,这些值大家可根据系统需求自行定义。本案例中是写死的,当然,在实际项目中应当根据登录账户信息结合数据库进行赋值。

  2、FormsAuthenticationTicket基于forms的验证

构建基于forms的验证机制过程如下: 
 1,设置IIS为可匿名访问和asp.net web.config中设置为form验证,配置webConfig,如下:

    <!--用户没有授权时 自动退回登陆界面-->
<authentication mode="Forms">
<forms loginUrl="~/Home/Login" timeout="" path="/" />
</authentication>

 2,检索数据存储验证用户,并检索角色(其实就是登录验证) 
 3,使用FormsAuthenticationTicket创建一个Cookie并回发到客户端,并存储

关于2、3两步,我以代码示例:

我创建的登录Model如下:

public class UserLogin
{
private readonly object LOCK = new object();
Maticsoft.BLL.YX_UserInfo Bll = new Maticsoft.BLL.YX_UserInfo();
Maticsoft.Model.YX_UserInfo Mol = new Maticsoft.Model.YX_UserInfo();
//
[Required(ErrorMessage = "请输入账户号码/手机号")]
[RegularExpression(@"^1[3458][0-9]{9}$", ErrorMessage = "手机号格式不正确")]
public string UserName { get; set; } [Required(ErrorMessage="请输入账户密码")]
[DataType(DataType.Password,ErrorMessage="密码格式不正确")]
[MinLength(, ErrorMessage = "密码长度介于6~15位之间")]
[MaxLength(, ErrorMessage = "密码长度介于6~15位之间")]
public string UserPwd { get; set; } public bool LoginAction()
{
lock (LOCK)
{
DataTable dt = Bll.GetList(" Uname='" + CommonMethod.CheckParamThrow(UserName) + "' and Upwd='" + CommonMethod.Md532(UserPwd) + "' and flat1=1").Tables[];
if (dt.Rows.Count > )
{
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
,
UserName,
DateTime.Now,
DateTime.Now.AddMinutes(),
false,
"admins,vip",
"/"
);
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
System.Web.HttpCookie authCookie = new System.Web.HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
System.Web.HttpContext.Current.Response.Cookies.Add(authCookie);
return true;
}
else
{
return false;
}
}
}
}

上述代码中

数据库验证成功,我们将用户信息存入Cookies,

然后我们在Global中解析这个Cookies,然后把解析的结果赋值给:HttpContext.User

代码如下:

        /// <summary>
/// 登录验证、s授权
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
FormsAuthenticationTicket authTicket = null;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch (Exception ex)
{
return;
}
string[] roles = authTicket.UserData.Split(',');
FormsIdentity id = new FormsIdentity(authTicket);
GenericPrincipal principal = new GenericPrincipal(id, roles);
Context.User = principal;//存到HttpContext.User中    
}

Context.User一旦被赋值成功,我们就可以访问那些有权限限制的方法。代码如下:

        [Authorize(Roles = "admins")]
public ActionResult UserCenter()
{
return View();
}

SO,搞懂了本质,一切都可以解决。

补充:本人登录代码如下:

前端 Login.cshtml

@{
ViewBag.Title = "登录";
}
@section css
{
<link href="~/Content/login.css" rel="stylesheet" />
}
<form id="form1">
<div class="wrap loginBox">
<div class="logo"><img src="/images/logo.png"/></div>
<div class="head">
<ul>
<li><input type="text" id="UserName" name="UserName" class="text n2" placeholder="手机号码" /></li>
<li><input type="password" id="UserPwd" name="UserPwd" class="text n3" placeholder="密码" /></li>
</ul>
</div>
<div class="body">
<a href="JavaScript:void(0)" class="btn btn-blue" onclick="Login()">立即登录</a>
@*<a href="JavaScript:void(0)" class="btn btn-yell">逗包账号登录</a>*@
</div>
<div class="foot">
<a href="JavaScript:void(0)">忘记密码?</a><a href="JavaScript:void(0)">账号注册</a>
</div>
</div>
</form>
<script type="text/javascript">
function Login() {
var UserName = $("#UserName").val();
var UserPwd = $("#UserPwd").val();
$(document).ready(function (data) {
$.ajax({
url: "/home/Login",
type: "post",
contentType: "application/json",
dataType: "text",
data: JSON.stringify({ UserName: UserName, UserPwd: UserPwd }),
success: function (result, status) {
if (result == "") {
//登录成功 跳转
location.href = "http://www.baidu.com";
}
else {
alert(result);//弹出错误码
}
},
error: function (error) {
alert(error);
}
});
});
}
</script>

后端 HomeController.cs:

    public class HomeController : Controller
{
public ActionResult Index()
{
return RedirectToAction("Login");
} public ActionResult Login()
{
return View();
} [HttpPost]
public object Login(UserLogin LoginMol)
{
if (NetworkHelper.Ping())//判断当前是否有网络
{
if (ModelState.IsValid)//是否通过Model验证
{
if (LoginMol.LoginAction())
{
return ;
}
else
{
return "账户或密码有误";
}
}
else
{
//读取错误信息
StringBuilder sb = new StringBuilder("");
var errors = ModelState.Values;
foreach (var item in errors)
{
foreach (var item2 in item.Errors)
{
if (!string.IsNullOrEmpty(item2.ErrorMessage))
{
if (string.IsNullOrEmpty(sb.ToString()))
{
sb.AppendLine(item2.ErrorMessage);//读取一个错误信息 并返回
}
}
}
}
return sb.ToString();
}
}
else
{
return "当前无网络,请稍后重试";
}
}
}

上述既是完整登录代码,谢谢!

@陈卧龙的博客

MVC 登录认证与授权及读取登录错误码的更多相关文章

  1. Shiro+Mybatis实现登录认证、授权功能

    Shiro+Mybatis实现登录认证.授权功能 一.实现登录认证功能 1.流程: 跟据用户提交表单的账号,经Mybatis框架在数据库中查出User对象: 如果User为空,则会抛出异常:Unkno ...

  2. SpringBoot日记——Spring的安全配置-登录认证与授权

    安全是每个项目开发中都需要考虑的,比如权限控制,安全认证,防止漏洞攻击等. 比较常见的安全框架有:Apache的shiro.Spring Security等等,相信用shiro的用户群体更多,而sec ...

  3. 详解登录认证及授权--Shiro系列(一)

    Apache Shiro 是一个强大而灵活的开源安全框架,它干净利落地处理身份认证,授权,企业会话管理和加密.Apache Shiro 的首要目标是易于使用和理解.安全有时候是很复杂的,甚至是痛苦的, ...

  4. OAuth2.0认证和授权以及单点登录

    https://www.cnblogs.com/shizhiyi/p/7754721.html OAuth2.0认证和授权机制讲解 2017-10-30 15:33 by shizhiyi, 2273 ...

  5. SpringBoot应用篇(二):SpringSecurity实现带验证码的登录认证 附代码

    一.文章简介 本文简要介绍了spring security的基本原理和实现,并基于springboot整合了spring security实现了基于数据库管理的用户的登录和登出,登录过程实现了验证码的 ...

  6. 【项目实践】一文带你搞定Session和JWT的登录认证方式

    以项目驱动学习,以实践检验真知 前言 登录认证,估计是所有系统中最常见的功能了,并且也是最基础.最重要的功能.为了做好这一块而诞生了许多安全框架,比如最常见的Shiro.Spring Security ...

  7. 来吧学学.Net Core之登录认证与跨域资源使用

    序言 学习core登录认证与跨域资源共享是越不过的砍,所以我在学习中同样也遇到啦这两个问题,今天我们就用示例来演示下使用下这2个技术点吧. 本篇主要内容如下: 1.展示一个登录认证的简单示例 2.跨域 ...

  8. Shiro 登录认证源码详解

    Shiro 登录认证源码详解 Apache Shiro 是一个强大且灵活的 Java 开源安全框架,拥有登录认证.授权管理.企业级会话管理和加密等功能,相比 Spring Security 来说要更加 ...

  9. 基于SpringSecurity和JWT的用户访问认证和授权

    发布时间:2018-12-03   技术:springsecurity+jwt+java+jpa+mysql+mysql workBench   概述 基于SpringSecurity和JWT的用户访 ...

随机推荐

  1. Antialiasing with Transparency

    Antialiasing with Transparency This sample demonstrates the GeForce 7 Series per-primitive super-sam ...

  2. mysql 导入导出.sql文件

    备份数据库(包含全部表和全部存储过程):C:\Documents and Settings\Administrator>mysqldump -h localhost -u root -p -R ...

  3. Linux 每天自动备份mysql数据库的方法

    Linux 每天自动备份mysql数据库的方法 作者: 字体:[增加 减小] 类型:转载   linux下为了安全有时候需要自动备份mysql数据库,下面是具体的实现步骤.   /usr/bin为my ...

  4. java TimeUnit synchronized demo

    import java.util.concurrent.TimeUnit; public class TestCalc { private static boolean stopRequested=f ...

  5. Jquery手册

    1.jQuery 选择器: 选择器 实例 选取 * $("*") 所有元素 #id $("#lastname") id="lastname" ...

  6. java类加载过程

    类(型)的生命周期--装载.连接.初始化.卸载 Java虚拟机通过装载.连接和初始化一个Java类型,使该类型可以被正在运行的Java程序所使用. 1.       装载 装载阶段包括三个基本动作: ...

  7. ArcGIS中添加进自定义的ttf字符标记符号

    原文:ArcGIS中添加进自定义的ttf字符标记符号 ArcGIS系统中的样式可能不能满足实际生产需要,为了实现快速制图,可自定义一些样式,以便重复利用. 1.   制作的符号库 使用 FontCre ...

  8. Top 10 Free Wireless Network hacking/monitoring tools for ethical hackers and businesses

    There are lots of free tools available online to get easy access to the WiFi networks intended to he ...

  9. E1114 Temp Ambient

    这2天DELL服务器的指示灯变为了黄色 ,显示“ E1114 Ambient Temp exceeds allowed range“  原来是周围环境温度超出了许可范围 ,难道最近的天真的是太冷了 ”

  10. Appium 已支持中文输入

    Appium 1.3.3以上. java: capabilities增加下面两项: capabilities.setCapability("unicodeKeyboard", &q ...