Asp.net MVC系列教程9——控制器基类 主要做登录用户、权限认证、日志记录等工作

作者 Guanghui Wang 日期 2017-02-23
c#

简述

本文转自http://yuangang.cnblogs.com并加以整理。 今天我们来写一个控制器基类 主要做登录用户、权限认证、日志记录等工作

索引

Asp.net MVC项目系列教程

项目开始

一、在Controllers文件夹下新建一个控制器BaseController

用于控制器基类,主要做登录用户、权限认证、日志记录等工作

二、声明公共变量和容器

变量主要用于我们查询分页的时候用户传递关键字、页码和分页条数

这个用户容器 主要是用户后台用户的一些操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#region 公用变量
/// <summary>
/// 查询关键词
/// </summary>
public string Keywords { get; set; }
/// <summary>
/// 视图传递的分页页码
/// </summary>
public int Page { get; set; }
/// <summary>
/// 视图传递的分页条数
/// </summary>
public int Pagesize { get; set; }

/// <summary>
/// 用户容器,公用
/// </summary>
public IUserManage UserManage = Spring.Context.Support.ContextRegistry.GetContext().GetObject("Service.User") as IUserManage;
#endregion

三、获取当前用户对象

从Sesssion中获取用户对象,Session过期后 通过 Cookies重新获取用户对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/// <summary>
/// 获取当前用户对象
/// </summary>
public Account CurrentUser
{
get
{
//从Session中获取用户对象
if (SessionHelper.GetSession("CurrentUser") != null)
{
return SessionHelper.GetSession("CurrentUser") as Account;
}
//Session过期 通过Cookies中的信息 重新获取用户对象 并存储于Session中
var account = UserManage.GetAccountByCookie();
SessionHelper.SetSession("CurrentUser", account);
return account;
}
}

四、重写OnActionExecuting方法

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
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
//登录用户验证 1、判断Session对象是否存在 || 2、登录验证
if (filterContext.HttpContext.Session == null || this.CurrentUser == null)
{
filterContext.HttpContext.Response.Write(
" <script type='text/javascript'> alert('~登录已过期,请重新登录');window.top.location='/'; </script>");
filterContext.RequestContext.HttpContext.Response.End();
filterContext.Result = new EmptyResult();
return;
}

#region 公共Get变量
//分页页码
string p = filterContext.HttpContext.Request["page"];
Page = string.IsNullOrEmpty(p) ? 1 : int.Parse(p);


//搜索关键词
string search = filterContext.HttpContext.Request.QueryString["search"];
if (!string.IsNullOrEmpty(search))
{
Keywords = search;
}
//显示分页条数
string size = filterContext.HttpContext.Request.QueryString["example_length"]; //todo: change name
if (!string.IsNullOrEmpty(size) && System.Text.RegularExpressions.Regex.IsMatch(size.ToString(), @"^\d+$"))
{
Pagesize = int.Parse(size.ToString());
}
else
{
Pagesize = 10;
}
#endregion

}

五、模块权限验证功能

  1. 根据模块别名验证对应模块
  2. 根据模块操作Action验证是否可操作按钮。

如果用户对相应的模块没有相应的操作权限(添加、修改、删除、审核、发布等等,包含自定义操作类型),我们拒绝执行。网站的权限判断是非常普遍的需求,只要自定义一个类继承自AuthorizeAttribute或者实现IAuthorizeFilter,重写相关的判断逻辑就可以了。

原作者在basecontroller下面新建一个权限验证类UserAuthorizeAttribute,继承自AuthorizeAttribute。你也可以在合适的位置单独创建文件,会更好。

添加一个自定义的Attribute,通过AttributeUsage的Attribute来限定Attribute所施加的元素的类型。作为参数的AttributeTarges的值允许通过“或”操作来进行多个值得组合,如果你没有指定参数,那么默认参数就是All 。

AttributeUsage除了继承Attribute的方法和属性之外,还定义了以下三个属性:

  • AllowMultiple: 表示是否可以对一个程序元素施加多个Attribute
  • Inherited: 表示是否施加的Attribute 可以被派生类继承或者重载。
  • ValidOn: 指明Attribute可以被施加的元素的类型。
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class UserAuthorizeAttribute : AuthorizeAttribute
{
#region 字段和属性
/// <summary>
/// 模块别名,可配置更改
/// </summary>
public string ModuleAlias { get; set; }
/// <summary>
/// 权限动作
/// </summary>
public string OperationAction { get; set; }
/// <summary>
/// 权限访问控制器参数
/// </summary>
private string Sign { get; set; }

/// <summary>
/// 基类实例化
/// </summary>
public BaseController baseController = new BaseController();

#endregion

//权限验证
public override void OnAuthorization(AuthorizationContext filterContext)
{
//1、判断模块是否对应
if (string.IsNullOrEmpty(ModuleAlias))
{
filterContext.HttpContext.Response.Write(" <script type='text/javascript'> alert('^您没有访问该页面的权限!'); </script>");
filterContext.RequestContext.HttpContext.Response.End();
filterContext.Result = new EmptyResult();
return;
}

//2、判断用户是否存在
if (baseController.CurrentUser == null)
{
filterContext.HttpContext.Response.Write(" <script type='text/javascript'> alert('^登录已过期,请重新登录!');window.top.location='/'; </script>");
filterContext.RequestContext.HttpContext.Response.End();
filterContext.Result = new EmptyResult();
return;
}

//对比变量,用于权限认证
string alias = ModuleAlias;

#region 配置Sign调取控制器标识
Sign = filterContext.RequestContext.HttpContext.Request.QueryString["sign"];
if (!string.IsNullOrEmpty(Sign))
{
if (("," + ModuleAlias.ToLower()).Contains("," + Sign.ToLower()))
{
alias = Sign;
filterContext.Controller.ViewData["Sign"] = Sign;
}
}
#endregion

//3、调用下面的方法,验证是否有访问此页面的权限,查看加操作
int moduleId = baseController.CurrentUser.Modules.Where(p => p.ALIAS.ToLower() == alias.ToLower()).Select(p => p.ID).FirstOrDefault();
bool _blAllowed = IsAllowed(baseController.CurrentUser, moduleId, OperationAction);
if (!_blAllowed)
{
filterContext.HttpContext.Response.Write(" <script type='text/javascript'> alert('您没有访问当前页面的权限!');</script>");
filterContext.RequestContext.HttpContext.Response.End();
filterContext.Result = new EmptyResult();
return;
}

//4、有权限访问页面,将此页面的权限集合传给页面
filterContext.Controller.ViewData["PermissionList"] = GetPermissByJson(baseController.CurrentUser, moduleId);
}

/// <summary>
/// 获取操作权限Json字符串,供视图JS判断使用。前台按钮没有这个权限就移除掉
/// </summary>
private string GetPermissByJson(Account account, int moduleId)
{
//操作权限
var _varPerListThisModule = account.Permissions.Where(p => p.MODULEID == moduleId).Select(R => new { R.PERVALUE }).ToList();
return Common.JsonHelper.JsonConverter.Serialize(_varPerListThisModule);
}

/// <summary>
/// 功能描述:判断用户是否有此模块的操作权限。
/// </summary>
private bool IsAllowed(Account user, int moduleId, string action)
{
//判断入口
if (user == null || user.Id <= 0 || moduleId == 0 || string.IsNullOrEmpty(action)) return false;
//验证权限
var permission = user.Permissions.Where(p => p.MODULEID == moduleId);
action = action.Trim(',');
if (action.IndexOf(',') > 0)
{
permission = permission.Where(p => action.ToLower().Contains(p.PERVALUE.ToLower()));
}
else
{
permission = permission.Where(p => p.PERVALUE.ToLower() == action.ToLower());
}
return permission.Any();
}
}

/// <summary>
/// 模型去重,非常重要
/// add yuangang by 2016-05-25
/// </summary>
public class ModuleDistinct : IEqualityComparer<Domain.SYS_MODULE>
{
public bool Equals(Domain.SYS_MODULE x, Domain.SYS_MODULE y)
{
return x.ID == y.ID;
}

public int GetHashCode(Domain.SYS_MODULE obj)
{
return obj.ToString().GetHashCode();
}
}

后面我们就用到这个基类,我先给大家看一下这个权限认证在后台是如何使用的,加上这一句就OK了