写在前面

Forms认证示意图

Forms 认证即是表单认证,需提供身份 id 和密码 password 的进行认证和授权管理。

下面看看他的工作方式:

Forms认证示意图

新建项目

创建一个 ASP.NET WEB 项目,勾选 MVC 和 WEB API

本案例使用的 MVC4 框架演示

创建 ASP.NET WEB 项目

打开 http://localhost:54125/,效果图:

效果图

Look,页面没有做任何权限控制,显示正常。

接下来给 HomeController/Index 加上 [Authorize] 特性

1
2
3
4
5
6
7
8
public class HomeController : Controller
{
[Authorize]
public ActionResult Index()
{
return View();
}
}
  • [Authorize]:指定对控制器或操作方法的访问只限于满足授权要求的用户。
  • [AllowAnonymous]:表示一个特性,该特性用于标记在授权期间要跳过 System.Web.Mvc.AuthorizeAttribute 的控制器和操作。

访问 http://localhost:54125/

抛出异常 HTTP Error 401.0 - Unauthorized

站点抛出异常 HTTP Error 401.0 - Unauthorized

提示我们没有查看权限,因为我们在上面给 Index 设置了权限认证

1
2
[Authorize]
public ActionResult Index()

配置登录页

正常情况下,我们是不会抛出 401.01 黄页的

如果用户没有查看权限,我们会要求用户返回登录页完成认证操作

Web.Config 中启用 Forms 身份验证,并设置登录地址为 ~/Home/Login

system.web 节点中添加

1
2
3
4
<!-- 配置 Forms 身份认证 不允许匿名用户访问,否则跳转到 /Home/Login 页面 -->
<authentication mode="Forms">
<forms loginUrl="~/Home/Login" timeout="2880"/>
</authentication>

记得在 Home 控制器中添加 Login 登录页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public ActionResult Login()
{
return View();
}

[HttpPost]
public ActionResult Login(string returnUrl)
{
if (Request.HttpMethod == "POST")
{
var userName = Request["userName"];
var passWord = Request["passWord"];

if (userName == "admin" && passWord == "123")
{
var ticket = new FormsAuthenticationTicket(
1,
userName,
DateTime.Now,
DateTime.Now.AddMinutes(20),
true,
"role1,role2,role3",
"/"
);

var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket))
{
HttpOnly = true
};

HttpContext.Response.Cookies.Add(cookie);

if (string.IsNullOrEmpty(returnUrl))
{
return RedirectToAction("Index");
}
else
{
return Redirect(returnUrl);
}
}
}

ViewBag.ReturnUrl = returnUrl;

return View();
}

Index.cshtml 视图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@{
Layout = null;
}

<!DOCTYPE html>

<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Login</title>
</head>
<body>
<h1>Login</h1>
<form method="post">
<table>
<tr>
<td>userName</td>
<td><input name="userName" value="admin" /></td>
</tr>
<tr>
<td>passWord</td>
<td><input type="password" name="passWord" value="123" /></td>
</tr>
</table>
<button type="submit">登录</button>
</form>
</body>
</html>

好的,我们在访问一下 http://localhost:54125/

跳转登录页

如期跳转至认证页面!点击登录按钮,认证成功的话会跳回首页

认证成功回到首页

好了,如愿显示!至此,简单权限认证完成了。

添加角色功能

前边只是做了简单的登录认证,如果项目要求权限的认证粒度比较细的话,就不能满足了。

IndexNeedRole4 只对某 role4 开放

1
2
3
4
5
[MyAuthorize(Roles = "role4")]
public ActionResult IndexNeedRole4()
{
return View();
}

我们需要新建用于验证角色和用户名的 Authorize 特性:MyAuthorize

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
{
var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
var ticket = FormsAuthentication.Decrypt(cookie.Value);
var roles = ticket.UserData;

var inRoles = false;
foreach (var role in roles.Split(','))
{
if (Roles.Contains(role))
{
inRoles = true;
break;
}
}

return inRoles;
}
}

代码加好了,我们再试试:http://localhost:54125/Home/IndexNeedRole4

访问 /Home/IndexNeedRole4

返回正常,回到了权限认证界面。

点击登录,发现这个页面只是刷新了,所有 input 都清空了

这是正常的,因为在 Home/Login 里边登录逻辑的 ticket 角色只赋值了 role1,role2,role3

加上 role4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
···

if (userName == "admin" && passWord == "123")
{
var ticket = new FormsAuthenticationTicket(
1,
userName,
DateTime.Now,
DateTime.Now.AddMinutes(20),
true,
"role1,role2,role3,role4", //加上 role4
"/"
);

···

再次点击登录

再次访问 /Home/IndexNeedRole4

OK, 如期显示正常

参考链接

  1. 理解OAuth 2.0 - 阮一峰的网络日志
  2. 权限认证 - 随笔分类 - 漂亮的猫 - 博客园
  3. 权限认证机制 - 搬砖滴 - 博客园