前言:Web 用户的身份验证,及页面操作权限验证是B/S系统的基础功能,一个功能复杂的业务应用系统,通过角色授权来控制用户访问,本文通过Form认证,Mvc的Controller基类及Action的权限验证来实现Web系统登录,Mvc前端权限校验以及WebApi服务端的访问校验功能。

1. Web Form认证介绍

Web应用的访问方式因为是基于浏览器的Http地址请求,所以需要验证用户身份的合法性。目前常见的方式是Form认证,其处理逻辑描述如下:
1. 用户首先要在登录页面输入用户名和密码,然后登录系统,获取合法身份的票据,再执行后续业务处理操作;
2. 用户在没有登录的情况下提交Http页面访问请求,如果该页面不允许匿名访问,则直接跳转到登录页面;
3. 对于允许匿名访问的页面请求,系统不做权限验证,直接处理业务数据,并返回给前端;
4. 对于不同权限要求的页面Action操作,系统需要校验用户角色,计算权限列表,如果请求操作在权限列表中,则正常访问,如果不在权限列表中,则提示“未授权的访问操作”到异常处理页面。

2. WebApi 服务端Basic 方式验证

WebApi服务端接收访问请求,需要做安全验证处理,验证处理步骤如下:
1. 如果是合法的Http请求,在Http请求头中会有用户身份的票据信息,服务端会读取票据信息,并校验票据信息是否完整有效,如果满足校验要求,则进行业务数据的处理,并返回给请求发起方;
2. 如果没有票据信息,或者票据信息不是合法的,则返回“未授权的访问”异常消息给前端,由前端处理此异常。

3. 登录及权限验证流程

流程处理步骤说明:
1. 用户打开浏览器,并在地址栏中输入页面请求地址,提交;
2. 浏览器解析Http请求,发送到Web服务器;Web服务器验证用户请求,首先判断是否有登录的票据信息;
3. 用户没有登录票据信息,则跳转到登录页面;
4. 用户输入用户名和密码信息;
5. 浏览器提交登录表单数据给Web服务器;
6. Web服务需要验证用户名和密码是否匹配,发送api请求给api服务器;
7. api用户账户服务根据用户名,读取存储在数据库中的用户资料,判断密码是否匹配;
1)如果用户名和密码不匹配,则提示密码错误等信息,然该用户重新填写登录资料;
2)如果验证通过,则保存用户票据信息;
8. 接第3步,如果用户有登录票据信息,则跳转到用户请求的页面;
9. 验证用户对当前要操作的页面或页面元素是否有权限操作,首先需要发起api服务请求,获取用户的权限数据;
10. api用户权限服务根据用户名,查找该用户的角色信息,并计算用户权限列表,封装为Json数据并返回;
11. 当用户有权限操作页面或页面元素时,跳转到页面,并由页面Controller提交业务数据处理请求到api服务器;
   如果用户没有权限访问该页面或页面元素时,则显示“未授权的访问操作”,跳转到系统异常处理页面。
12. api业务服务处理业务逻辑,并将结果以Json 数据返回;
13. 返回渲染后的页面给浏览器前端,并呈现业务数据到页面;
14. 用户填写业务数据,或者查找业务数据;
15. 当填写或查找完业务数据后,用户提交表单数据;
16. 浏览器脚本提交get,post等请求给web服务器,由web服务器再次解析请求操作,重复步骤2的后续流程;
17. 当api服务器验证用户身份是,没有可信用户票据,系统提示“未授权的访问操作”,跳转到系统异常处理页面。

4. Mvc前端代码示例

4.1 用户登录AccountController

  1. <span style="font-size: 18px;"> </span><span style="font-size: 14px;">
  2. public class AccountController : Controller
  3. {
  4. //
  5. // GET: /Logon/
  6. public ActionResult Login(string returnUrl)
  7. {
  8. ViewBag.ReturnUrl = returnUrl;
  9. return View();
  10. }
  11. [HttpPost]
  12. public ActionResult Logon(LoginUser loginUser, string returnUrl)
  13. {
  14. string strUserName = loginUser.UserName;
  15. string strPassword = loginUser.Password;
  16. var accountModel = new AccountModel();
  17. //验证用户是否是系统注册用户
  18. if (accountModel.ValidateUserLogin(strUserName, strPassword))
  19. {
  20. if (Url.IsLocalUrl(returnUrl))
  21. {
  22. //创建用户ticket信息
  23. accountModel.CreateLoginUserTicket(strUserName, strPassword);
  24. //读取用户权限数据
  25. accountModel.GetUserAuthorities(strUserName);
  26. return new RedirectResult(returnUrl);
  27. }
  28. else
  29. {
  30. return RedirectToAction("Index", "Home");
  31. }
  32. }
  33. else
  34. {
  35. throw new ApplicationException("无效登录用户!");
  36. }
  37. }
  38. /// <summary>
  39. /// 用户注销,注销之前,清除用户ticket
  40. /// </summary>
  41. /// <returns></returns>
  42. [HttpPost]
  43. public ActionResult Logout()
  44. {
  45. var accountModel = new AccountModel();
  46. accountModel.Logout();
  47. return RedirectToAction("Login", "Account");
  48. }
  49. }</span>
  1. <span style="font-size:18px;"> </span><span style="font-size:14px;">public class AccountController : Controller
  2. {
  3. //
  4. // GET: /Logon/
  5. public ActionResult Login(string returnUrl)
  6. {
  7. ViewBag.ReturnUrl = returnUrl;
  8. return View();
  9. }
  10. [HttpPost]
  11. public ActionResult Logon(LoginUser loginUser, string returnUrl)
  12. {
  13. string strUserName = loginUser.UserName;
  14. string strPassword = loginUser.Password;
  15. var accountModel = new AccountModel();
  16. //验证用户是否是系统注册用户
  17. if (accountModel.ValidateUserLogin(strUserName, strPassword))
  18. {
  19. if (Url.IsLocalUrl(returnUrl))
  20. {
  21. //创建用户ticket信息
  22. accountModel.CreateLoginUserTicket(strUserName, strPassword);
  23. //读取用户权限数据
  24. accountModel.GetUserAuthorities(strUserName);
  25. return new RedirectResult(returnUrl);
  26. }
  27. else
  28. {
  29. return RedirectToAction("Index", "Home");
  30. }
  31. }
  32. else
  33. {
  34. throw new ApplicationException("无效登录用户!");
  35. }
  36. }
  37. /// <summary>
  38. /// 用户注销,注销之前,清除用户ticket
  39. /// </summary>
  40. /// <returns></returns>
  41. [HttpPost]
  42. public ActionResult Logout()
  43. {
  44. var accountModel = new AccountModel();
  45. accountModel.Logout();
  46. return RedirectToAction("Login", "Account");
  47. }
  48. }</span>

4.2 用户模型AccountModel

  1. <span style="font-size: 14px;">
  2. public class AccountModel
  3. {
  4. /// <summary>
  5. /// 创建登录用户的票据信息
  6. /// </summary>
  7. /// <param name="strUserName"></param>
  8. internal void CreateLoginUserTicket(string strUserName, string strPassword)
  9. {
  10. //构造Form验证的票据信息
  11. FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, strUserName, DateTime.Now, DateTime.Now.AddMinutes(90),
  12. true, string.Format("{0}:{1}", strUserName, strPassword), FormsAuthentication.FormsCookiePath);
  13. string ticString = FormsAuthentication.Encrypt(ticket);
  14. //把票据信息写入Cookie和Session
  15. //SetAuthCookie方法用于标识用户的Identity状态为true
  16. HttpContext.Current.Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, ticString));
  17. FormsAuthentication.SetAuthCookie(strUserName, true);
  18. HttpContext.Current.Session["USER_LOGON_TICKET"] = ticString;
  19. //重写HttpContext中的用户身份,可以封装自定义角色数据;
  20. //判断是否合法用户,可以检查:HttpContext.User.Identity.IsAuthenticated的属性值
  21. string[] roles = ticket.UserData.Split(',');
  22. IIdentity identity = new FormsIdentity(ticket);
  23. IPrincipal principal = new GenericPrincipal(identity, roles);
  24. HttpContext.Current.User = principal;
  25. }
  26. /// <summary>
  27. /// 获取用户权限列表数据
  28. /// </summary>
  29. /// <param name="userName"></param>
  30. /// <returns></returns>
  31. internal string GetUserAuthorities(string userName)
  32. {
  33. //从WebApi 访问用户权限数据,然后写入Session
  34. string jsonAuth = "[{\"Controller\": \"SampleController\", \"Actions\":\"Apply,Process,Complete\"}, {\"Controller\": \"Product\", \"Actions\": \"List,Get,Detail\"}]";
  35. var userAuthList = ServiceStack.Text.JsonSerializer.DeserializeFromString(jsonAuth, typeof(UserAuthModel[]));
  36. HttpContext.Current.Session["USER_AUTHORITIES"] = userAuthList;
  37. return jsonAuth;
  38. }
  39. /// <summary>
  40. /// 读取数据库用户表数据,判断用户密码是否匹配
  41. /// </summary>
  42. /// <param name="name"></param>
  43. /// <param name="password"></param>
  44. /// <returns></returns>
  45. internal bool ValidateUserLogin(string name, string password)
  46. {
  47. //bool isValid = password == passwordInDatabase;
  48. return true;
  49. }
  50. /// <summary>
  51. /// 用户注销执行的操作
  52. /// </summary>
  53. internal void Logout()
  54. {
  55. FormsAuthentication.SignOut();
  56. }
  57. }</span>
  1. <span style="font-size:14px;">public class AccountModel
  2. {
  3. /// <summary>
  4. /// 创建登录用户的票据信息
  5. /// </summary>
  6. /// <param name="strUserName"></param>
  7. internal void CreateLoginUserTicket(string strUserName, string strPassword)
  8. {
  9. //构造Form验证的票据信息
  10. FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, strUserName, DateTime.Now, DateTime.Now.AddMinutes(90),
  11. true, string.Format("{0}:{1}", strUserName, strPassword), FormsAuthentication.FormsCookiePath);
  12. string ticString = FormsAuthentication.Encrypt(ticket);
  13. //把票据信息写入Cookie和Session
  14. //SetAuthCookie方法用于标识用户的Identity状态为true
  15. HttpContext.Current.Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, ticString));
  16. FormsAuthentication.SetAuthCookie(strUserName, true);
  17. HttpContext.Current.Session["USER_LOGON_TICKET"] = ticString;
  18. //重写HttpContext中的用户身份,可以封装自定义角色数据;
  19. //判断是否合法用户,可以检查:HttpContext.User.Identity.IsAuthenticated的属性值
  20. string[] roles = ticket.UserData.Split(',');
  21. IIdentity identity = new FormsIdentity(ticket);
  22. IPrincipal principal = new GenericPrincipal(identity, roles);
  23. HttpContext.Current.User = principal;
  24. }
  25. /// <summary>
  26. /// 获取用户权限列表数据
  27. /// </summary>
  28. /// <param name="userName"></param>
  29. /// <returns></returns>
  30. internal string GetUserAuthorities(string userName)
  31. {
  32. //从WebApi 访问用户权限数据,然后写入Session
  33. string jsonAuth = "[{\"Controller\": \"SampleController\", \"Actions\":\"Apply,Process,Complete\"}, {\"Controller\": \"Product\", \"Actions\": \"List,Get,Detail\"}]";
  34. var userAuthList = ServiceStack.Text.JsonSerializer.DeserializeFromString(jsonAuth, typeof(UserAuthModel[]));
  35. HttpContext.Current.Session["USER_AUTHORITIES"] = userAuthList;
  36. return jsonAuth;
  37. }
  38. /// <summary>
  39. /// 读取数据库用户表数据,判断用户密码是否匹配
  40. /// </summary>
  41. /// <param name="name"></param>
  42. /// <param name="password"></param>
  43. /// <returns></returns>
  44. internal bool ValidateUserLogin(string name, string password)
  45. {
  46. //bool isValid = password == passwordInDatabase;
  47. return true;
  48. }
  49. /// <summary>
  50. /// 用户注销执行的操作
  51. /// </summary>
  52. internal void Logout()
  53. {
  54. FormsAuthentication.SignOut();
  55. }
  56. }</span>

4.3 控制器基类WebControllerBase

  1. <span style="font-size: 14px;">/// <summary>
  2. /// 前端Mvc控制器基类
  3. /// </summary>
  4. [Authorize]
  5. public abstract class WebControllerBase : Controller
  6. {
  7. /// <summary>
  8. /// 对应api的Url
  9. /// </summary>
  10. public string ApiUrl
  11. {
  12. get;
  13. protected set;
  14. }
  15. /// <summary>
  16. /// 用户权限列表
  17. /// </summary>
  18. public UserAuthModel[] UserAuthList
  19. {
  20. get
  21. {
  22. return AuthorizedUser.Current.UserAuthList;
  23. }
  24. }
  25. /// <summary>
  26. /// 登录用户票据
  27. /// </summary>
  28. public string UserLoginTicket
  29. {
  30. get
  31. {
  32. return AuthorizedUser.Current.UserLoginTicket;
  33. }
  34. }
  35. }</span>
  1. <span style="font-size:14px;">/// <summary>
  2. /// 前端Mvc控制器基类
  3. /// </summary>
  4. [Authorize]
  5. public abstract class WebControllerBase : Controller
  6. {
  7. /// <summary>
  8. /// 对应api的Url
  9. /// </summary>
  10. public string ApiUrl
  11. {
  12. get;
  13. protected set;
  14. }
  15. /// <summary>
  16. /// 用户权限列表
  17. /// </summary>
  18. public UserAuthModel[] UserAuthList
  19. {
  20. get
  21. {
  22. return AuthorizedUser.Current.UserAuthList;
  23. }
  24. }
  25. /// <summary>
  26. /// 登录用户票据
  27. /// </summary>
  28. public string UserLoginTicket
  29. {
  30. get
  31. {
  32. return AuthorizedUser.Current.UserLoginTicket;
  33. }
  34. }
  35. }</span>

4.4 权限属性RequireAuthorizationAttribute

  1. <span style="font-size: 14px;">/// <summary>
  2. /// 权限验证属性类
  3. /// </summary>
  4. public class RequireAuthorizeAttribute : AuthorizeAttribute
  5. {
  6. /// <summary>
  7. /// 用户权限列表
  8. /// </summary>
  9. public UserAuthModel[] UserAuthList
  10. {
  11. get
  12. {
  13. return AuthorizedUser.Current.UserAuthList;
  14. }
  15. }
  16. /// <summary>
  17. /// 登录用户票据
  18. /// </summary>
  19. public string UserLoginTicket
  20. {
  21. get
  22. {
  23. return AuthorizedUser.Current.UserLoginTicket;
  24. }
  25. }
  26. public override void OnAuthorization(AuthorizationContext filterContext)
  27. {
  28. base.OnAuthorization(filterContext);
  29. ////验证是否是登录用户
  30. var identity = filterContext.HttpContext.User.Identity;
  31. if (identity.IsAuthenticated)
  32. {
  33. var actionName = filterContext.ActionDescriptor.ActionName;
  34. var controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
  35. //验证用户操作是否在权限列表中
  36. if (HasActionQulification(actionName, controllerName, identity.Name))
  37. if (!string.IsNullOrEmpty(UserLoginTicket))
  38. //有效登录用户,有权限访问此Action,则写入Cookie信息
  39. filterContext.HttpContext.Response.Cookies[FormsAuthentication.FormsCookieName].Value = UserLoginTicket;
  40. else
  41. //用户的Session, Cookie都过期,需要重新登录
  42. filterContext.HttpContext.Response.Redirect("~/Account/Login", false);
  43. else
  44. //虽然是登录用户,但没有该Action的权限,跳转到“未授权访问”页面
  45. filterContext.HttpContext.Response.Redirect("~/Home/UnAuthorized", true);
  46. }
  47. else
  48. {
  49. //未登录用户,则判断是否是匿名访问
  50. var attr = filterContext.ActionDescriptor.GetCustomAttributes(true).OfType<AllowAnonymousAttribute>();
  51. bool isAnonymous = attr.Any(a => a is AllowAnonymousAttribute);
  52. if (!isAnonymous)
  53. //未验证(登录)的用户, 而且是非匿名访问,则转向登录页面
  54. filterContext.HttpContext.Response.Redirect("~/Account/Login", true);
  55. }
  56. }
  57. /// <summary>
  58. /// 从权限列表验证用户是否有权访问Action
  59. /// </summary>
  60. /// <param name="actionName"></param>
  61. /// <param name="controllerName"></param>
  62. /// <returns></returns>
  63. private bool HasActionQulification(string actionName, string controllerName, string userName)
  64. {
  65. //从该用户的权限数据列表中查找是否有当前Controller和Action的item
  66. var auth = UserAuthList.FirstOrDefault(a =>
  67. {
  68. bool rightAction = false;
  69. bool rightController = a.Controller == controllerName;
  70. if (rightController)
  71. {
  72. string[] actions = a.Actions.Split(',');
  73. rightAction = actions.Contains(actionName);
  74. }
  75. return rightAction;
  76. });
  77. //此处可以校验用户的其它权限条件
  78. //var notAllowed = HasOtherLimition(userName);
  79. //var result = (auth != null) && notAllowed;
  80. //return result;
  81. return (auth != null);
  82. }
  83. }</span>
  1. <span style="font-size:14px;">/// <summary>
  2. /// 权限验证属性类
  3. /// </summary>
  4. public class RequireAuthorizeAttribute : AuthorizeAttribute
  5. {
  6. /// <summary>
  7. /// 用户权限列表
  8. /// </summary>
  9. public UserAuthModel[] UserAuthList
  10. {
  11. get
  12. {
  13. return AuthorizedUser.Current.UserAuthList;
  14. }
  15. }
  16. /// <summary>
  17. /// 登录用户票据
  18. /// </summary>
  19. public string UserLoginTicket
  20. {
  21. get
  22. {
  23. return AuthorizedUser.Current.UserLoginTicket;
  24. }
  25. }
  26. public override void OnAuthorization(AuthorizationContext filterContext)
  27. {
  28. base.OnAuthorization(filterContext);
  29. ////验证是否是登录用户
  30. var identity = filterContext.HttpContext.User.Identity;
  31. if (identity.IsAuthenticated)
  32. {
  33. var actionName = filterContext.ActionDescriptor.ActionName;
  34. var controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
  35. //验证用户操作是否在权限列表中
  36. if (HasActionQulification(actionName, controllerName, identity.Name))
  37. if (!string.IsNullOrEmpty(UserLoginTicket))
  38. //有效登录用户,有权限访问此Action,则写入Cookie信息
  39. filterContext.HttpContext.Response.Cookies[FormsAuthentication.FormsCookieName].Value = UserLoginTicket;
  40. else
  41. //用户的Session, Cookie都过期,需要重新登录
  42. filterContext.HttpContext.Response.Redirect("~/Account/Login", false);
  43. else
  44. //虽然是登录用户,但没有该Action的权限,跳转到“未授权访问”页面
  45. filterContext.HttpContext.Response.Redirect("~/Home/UnAuthorized", true);
  46. }
  47. else
  48. {
  49. //未登录用户,则判断是否是匿名访问
  50. var attr = filterContext.ActionDescriptor.GetCustomAttributes(true).OfType<AllowAnonymousAttribute>();
  51. bool isAnonymous = attr.Any(a => a is AllowAnonymousAttribute);
  52. if (!isAnonymous)
  53. //未验证(登录)的用户, 而且是非匿名访问,则转向登录页面
  54. filterContext.HttpContext.Response.Redirect("~/Account/Login", true);
  55. }
  56. }
  57. /// <summary>
  58. /// 从权限列表验证用户是否有权访问Action
  59. /// </summary>
  60. /// <param name="actionName"></param>
  61. /// <param name="controllerName"></param>
  62. /// <returns></returns>
  63. private bool HasActionQulification(string actionName, string controllerName, string userName)
  64. {
  65. //从该用户的权限数据列表中查找是否有当前Controller和Action的item
  66. var auth = UserAuthList.FirstOrDefault(a =>
  67. {
  68. bool rightAction = false;
  69. bool rightController = a.Controller == controllerName;
  70. if (rightController)
  71. {
  72. string[] actions = a.Actions.Split(',');
  73. rightAction = actions.Contains(actionName);
  74. }
  75. return rightAction;
  76. });
  77. //此处可以校验用户的其它权限条件
  78. //var notAllowed = HasOtherLimition(userName);
  79. //var result = (auth != null) && notAllowed;
  80. //return result;
  81. return (auth != null);
  82. }
  83. }</span>

4.5 业务Controller示例

  1. <span style="font-size: 14px;">
  2. public class ProductController : WebControllerBase
  3. {
  4. [AllowAnonymous]
  5. public ActionResult Query()
  6. {
  7. return View("ProductQuery");
  8. }
  9. [HttpGet]
  10. //[AllowAnonymous]
  11. [RequireAuthorize]
  12. public ActionResult Detail(string id)
  13. {
  14. var cookie = HttpContext.Request.Cookies;
  15. string url = base.ApiUrl + "/Get/" + id;
  16. HttpClient httpClient = HttpClientHelper.Create(url, base.UserLoginTicket);
  17. string result = httpClient.GetString();
  18. var model = JsonSerializer.DeserializeFromString<Product>(result);
  19. ViewData["PRODUCT_ADD_OR_EDIT"] = "E";
  20. return View("ProductForm", model);
  21. }
  22. }</span>
  1. <span style="font-size:14px;">public class ProductController : WebControllerBase
  2. {
  3. [AllowAnonymous]
  4. public ActionResult Query()
  5. {
  6. return View("ProductQuery");
  7. }
  8. [HttpGet]
  9. //[AllowAnonymous]
  10. [RequireAuthorize]
  11. public ActionResult Detail(string id)
  12. {
  13. var cookie = HttpContext.Request.Cookies;
  14. string url = base.ApiUrl + "/Get/" + id;
  15. HttpClient httpClient = HttpClientHelper.Create(url, base.UserLoginTicket);
  16. string result = httpClient.GetString();
  17. var model = JsonSerializer.DeserializeFromString<Product>(result);
  18. ViewData["PRODUCT_ADD_OR_EDIT"] = "E";
  19. return View("ProductForm", model);
  20. }
  21. }</span>

5.  WebApi 服务端代码示例

5.1 控制器基类ApiControllerBase

  1. /// <summary>
  2. /// Controller的基类,用于实现适合业务场景的基础功能
  3. /// </summary>
  4. /// <typeparam name="T"></typeparam>
  5. [BasicAuthentication]
  6. public abstract class ApiControllerBase : ApiController
  7. {
  8. }
  1. /// <summary>
  2. /// Controller的基类,用于实现适合业务场景的基础功能
  3. /// </summary>
  4. /// <typeparam name="T"></typeparam>
  5. [BasicAuthentication]
  6. public abstract class ApiControllerBase : ApiController
  7. {
  8. }

5.2 权限属性BaseAuthenticationAttribute

  1. /// <summary>
  2. /// 基本验证Attribtue,用以Action的权限处理
  3. /// </summary>
  4. public class BasicAuthenticationAttribute : ActionFilterAttribute
  5. {
  6. /// <summary>
  7. /// 检查用户是否有该Action执行的操作权限
  8. /// </summary>
  9. /// <param name="actionContext"></param>
  10. public override void OnActionExecuting(HttpActionContext actionContext)
  11. {
  12. //检验用户ticket信息,用户ticket信息来自调用发起方
  13. if (actionContext.Request.Headers.Authorization != null)
  14. {
  15. //解密用户ticket,并校验用户名密码是否匹配
  16. var encryptTicket = actionContext.Request.Headers.Authorization.Parameter;
  17. if (ValidateUserTicket(encryptTicket))
  18. base.OnActionExecuting(actionContext);
  19. else
  20. actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
  21. }
  22. else
  23. {
  24. //检查web.config配置是否要求权限校验
  25. bool isRquired = (WebConfigurationManager.AppSettings["WebApiAuthenticatedFlag"].ToString() == "true");
  26. if (isRquired)
  27. {
  28. //如果请求Header不包含ticket,则判断是否是匿名调用
  29. var attr = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().OfType<AllowAnonymousAttribute>();
  30. bool isAnonymous = attr.Any(a => a is AllowAnonymousAttribute);
  31. //是匿名用户,则继续执行;非匿名用户,抛出“未授权访问”信息
  32. if (isAnonymous)
  33. base.OnActionExecuting(actionContext);
  34. else
  35. actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
  36. }
  37. else
  38. {
  39. base.OnActionExecuting(actionContext);
  40. }
  41. }
  42. }
  43. /// <summary>
  44. /// 校验用户ticket信息
  45. /// </summary>
  46. /// <param name="encryptTicket"></param>
  47. /// <returns></returns>
  48. private bool ValidateUserTicket(string encryptTicket)
  49. {
  50. var userTicket = FormsAuthentication.Decrypt(encryptTicket);
  51. var userTicketData = userTicket.UserData;
  52. string userName = userTicketData.Substring(0, userTicketData.IndexOf(":"));
  53. string password = userTicketData.Substring(userTicketData.IndexOf(":") + 1);
  54. //检查用户名、密码是否正确,验证是合法用户
  55. //var isQuilified = CheckUser(userName, password);
  56. return true;
  57. }
  58. }
  1. /// <summary>
  2. /// 基本验证Attribtue,用以Action的权限处理
  3. /// </summary>
  4. public class BasicAuthenticationAttribute : ActionFilterAttribute
  5. {
  6. /// <summary>
  7. /// 检查用户是否有该Action执行的操作权限
  8. /// </summary>
  9. /// <param name="actionContext"></param>
  10. public override void OnActionExecuting(HttpActionContext actionContext)
  11. {
  12. //检验用户ticket信息,用户ticket信息来自调用发起方
  13. if (actionContext.Request.Headers.Authorization != null)
  14. {
  15. //解密用户ticket,并校验用户名密码是否匹配
  16. var encryptTicket = actionContext.Request.Headers.Authorization.Parameter;
  17. if (ValidateUserTicket(encryptTicket))
  18. base.OnActionExecuting(actionContext);
  19. else
  20. actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
  21. }
  22. else
  23. {
  24. //检查web.config配置是否要求权限校验
  25. bool isRquired = (WebConfigurationManager.AppSettings["WebApiAuthenticatedFlag"].ToString() == "true");
  26. if (isRquired)
  27. {
  28. //如果请求Header不包含ticket,则判断是否是匿名调用
  29. var attr = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().OfType<AllowAnonymousAttribute>();
  30. bool isAnonymous = attr.Any(a => a is AllowAnonymousAttribute);
  31. //是匿名用户,则继续执行;非匿名用户,抛出“未授权访问”信息
  32. if (isAnonymous)
  33. base.OnActionExecuting(actionContext);
  34. else
  35. actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
  36. }
  37. else
  38. {
  39. base.OnActionExecuting(actionContext);
  40. }
  41. }
  42. }
  43. /// <summary>
  44. /// 校验用户ticket信息
  45. /// </summary>
  46. /// <param name="encryptTicket"></param>
  47. /// <returns></returns>
  48. private bool ValidateUserTicket(string encryptTicket)
  49. {
  50. var userTicket = FormsAuthentication.Decrypt(encryptTicket);
  51. var userTicketData = userTicket.UserData;
  52. string userName = userTicketData.Substring(0, userTicketData.IndexOf(":"));
  53. string password = userTicketData.Substring(userTicketData.IndexOf(":") + 1);
  54. //检查用户名、密码是否正确,验证是合法用户
  55. //var isQuilified = CheckUser(userName, password);
  56. return true;
  57. }
  58. }

5.3 api服务Controller实例

  1. public class ProductController : ApiControllerBase
  2. {
  3. [HttpGet]
  4. public object Find(string id)
  5. {
  6. return ProductServiceInstance.Find(2);
  7. }
  8. // GET api/product/5
  9. [HttpGet]
  10. [AllowAnonymous]
  11. public Product Get(string id)
  12. {
  13. var headers = Request.Headers;
  14. var p = ProductServiceInstance.GetById<Product, EPProduct>(long.Parse(id));
  15. if (p == null)
  16. {
  17. throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest)
  18. Content = new StringContent("id3 not found"), ReasonPhrase = "product id not exist." });
  19. }
  20. return p;
  21. }
  22. }
  1. public class ProductController : ApiControllerBase
  2. {
  3. [HttpGet]
  4. public object Find(string id)
  5. {
  6. return ProductServiceInstance.Find(2);
  7. }
  8. // GET api/product/5
  9. [HttpGet]
  10. [AllowAnonymous]
  11. public Product Get(string id)
  12. {
  13. var headers = Request.Headers;
  14. var p = ProductServiceInstance.GetById<Product, EPProduct>(long.Parse(id));
  15. if (p == null)
  16. {
  17. throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest)
  18. Content = new StringContent("id3 not found"), ReasonPhrase = "product id not exist." });
  19. }
  20. return p;
  21. }
  22. }

6. 其它配置说明

6.1 Mvc前端Web.Config 配置

  1. <system.web>
  2. <compilation debug="true" targetFramework="4.5">
  3. <assemblies>
  4. <add assembly="System.Web.Http.Data.Helpers, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  5. </assemblies>
  6. </compilation>
  7. <httpRuntime targetFramework="4.5" />
  8. <authentication mode="Forms">
  9. <forms loginUrl="~/Account/Login" defaultUrl="~/Home/Index" protection="All" timeout="90" name=".AuthCookie"></forms>
  10. </authentication>
  11. <machineKey validationKey="3FFA12388DDF585BA5D35E7BC87E3F0AB47FBBEBD12240DD3BEA2BEAEC4ABA213F22AD27E8FAD77DCFEE306219691434908D193A17C1FC8DCE51B71A4AE54920" decryptionKey="ECB6A3AF9ABBF3F16E80685ED68DC74B0B13CCEE538EBBA97D0B893139683B3B" validation="SHA1" decryption="AES" />
  12. </system.web>
  1. <system.web>
  2. <compilation debug="true" targetFramework="4.5">
  3. <assemblies>
  4. <add assembly="System.Web.Http.Data.Helpers, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  5. </assemblies>
  6. </compilation>
  7. <httpRuntime targetFramework="4.5" />
  8. <authentication mode="Forms">
  9. <forms loginUrl="~/Account/Login" defaultUrl="~/Home/Index" protection="All" timeout="90" name=".AuthCookie"></forms>
  10. </authentication>
  11. <machineKey validationKey="3FFA12388DDF585BA5D35E7BC87E3F0AB47FBBEBD12240DD3BEA2BEAEC4ABA213F22AD27E8FAD77DCFEE306219691434908D193A17C1FC8DCE51B71A4AE54920" decryptionKey="ECB6A3AF9ABBF3F16E80685ED68DC74B0B13CCEE538EBBA97D0B893139683B3B" validation="SHA1" decryption="AES" />
  12. </system.web>

machineKey节点配置,是应用于对用户ticket数据加密和解密。

6.2 WebApi服务端Web.Config配置

  1. <system.web>
  2. <machineKey validationKey="3FF112388DDF585BA5D35E7BC87E3F0AB47FBBEBD12240DD3BEA2BEAEC4ABA213F22AD27E8FAD77DCFEE306219691434908D193A17C1FC8DCE51B71A4AE54920" decryptionKey="ECB6A3AF9ABBF3F16E80685ED68DC74B0B13CCEE538EBBA97D0B893139683B3B" validation="SHA1" decryption="AES" />
  3. </system.web>
  1. <system.web>
  2. <machineKey validationKey="3FF112388DDF585BA5D35E7BC87E3F0AB47FBBEBD12240DD3BEA2BEAEC4ABA213F22AD27E8FAD77DCFEE306219691434908D193A17C1FC8DCE51B71A4AE54920" decryptionKey="ECB6A3AF9ABBF3F16E80685ED68DC74B0B13CCEE538EBBA97D0B893139683B3B" validation="SHA1" decryption="AES" />
  3. </system.web>

machineKey节点配置,是应用于对用户ticket数据加密和解密。

7. 总结

Web系统的用户登录及页面操作权限验证在处理逻辑上比较复杂,需要考虑到Form认证、匿名访问,Session和Cookie存储,以及Session和Cookie的过期处理,本文实现了整个权限验证框架的基本功能,供系统架构设计人员以及Web开发人员参考。

转 Web用户的身份验证及WebApi权限验证流程的设计和实现的更多相关文章

  1. [置顶] Web用户的身份验证及WebApi权限验证流程的设计和实现 (不是Token驗證!!!不是Token驗證!!!都是基於用户身份的票据信息驗證!!!)

     转发 http://blog.csdn.net/besley/article/details/8516894 不是Token驗證!!!不是Token驗證!!!都是基於用户身份的票据信息驗證!!! [ ...

  2. Web用户的身份验证及WebApi权限验证流程的设计和实现 asp.net mvc AllowAnonymous 不起作用, asp.net mvc 匿名访问

    原文地址: https://blog.csdn.net/zjlovety/article/details/17095627 前言:Web 用户的身份验证,及页面操作权限验证是B/S系统的基础功能,一个 ...

  3. Web用户的身份验证及WebApi权限验证流程的设计和实现

    5. WebApi 服务端代码示例 5.1 控制器基类ApiControllerBase [csharp] view plaincopy   /// /// Controller的基类,用于实现适合业 ...

  4. Web用户的身份验证及WebApi权限验证流程的设计和实现(尾)

    5. WebApi 服务端代码示例 5.1 控制器基类ApiControllerBase [csharp] view plaincopy   /// /// Controller的基类,用于实现适合业 ...

  5. Web用户的身份验证及WebApi权限验证流程的设计和实现(续)

    4.4 权限属性RequireAuthorizationAttribute [csharp] view plaincopy   "font-size:14px;">/// / ...

  6. SpringAOP01 利用AOP实现权限验证、利用权限验证服务实现权限验证

    1 编程范式 1.1 面向过程 1.2 面向对象 1.3 面向切面编程 1.4 函数式编程 1.5 事件驱动编程 2 什么是面向切面编程 2.1 是一种编程范式,而不是一种编程语言 2.2 解决一些特 ...

  7. 学习总结之 WebApi 用户登录和匿名登录,及权限验证

    近些天,看了一些博客园大牛关于webApi项目的的文章,也有请教师兄一些问题,自己做了个Demo试了试,收获甚多.感谢感谢,下面是我一些学习的总结,如若有错的地方请多多指教!! WebApi登陆与身份 ...

  8. 简单两步快速实现shiro的配置和使用,包含登录验证、角色验证、权限验证以及shiro登录注销流程(基于spring的方式,使用maven构建)

    前言: shiro因为其简单.可靠.实现方便而成为现在最常用的安全框架,那么这篇文章除了会用简洁明了的方式讲一下基于spring的shiro详细配置和登录注销功能使用之外,也会根据惯例在文章最后总结一 ...

  9. [Abp 源码分析]十二、多租户体系与权限验证

    0.简介 承接上篇文章我们会在这篇文章详细解说一下 Abp 是如何结合 IPermissionChecker 与 IFeatureChecker 来实现一个完整的多租户系统的权限校验的. 1.多租户的 ...

随机推荐

  1. (NO.00001)iOS游戏SpeedBoy Lite成形记(十四)

    下面要启用场景的触摸功能,在GameScene.m的didLoadFromCCB方法里添加下面一行: self.userInteractionEnabled = YES; 然后还需要给GameScen ...

  2. Android重命名包名

    工程写的差不多了才发现原来用的包名还是自己尝试性的进行写代码的时候用到的.但apk的发布,google map api的申请等等方面都需要用到一个比较规范的包名.这就涉及到修改包名的问题. 包名一开始 ...

  3. 《java入门第一季》之类(String类常见方法小叙)

    String类下面的构造方法和一些常见的方法: /* * 字符串:就是由多个字符组成的一串数据.也可以看成是一个字符数组. * 通过查看API,可以知道 * A:字符串字面值"abc&quo ...

  4. Cocos2d中update与fixedUpdate的区别(四)

    关于fixedUpdate:方法的目的 现在,想象一下在小球飞行的位置1到8之间有一个移动的平台: 该平台不停地上升和下降.有些时候小球可以不碰到而飘过平台,有些时候小球会和平台发生碰撞: 这表示小球 ...

  5. mysql进阶(九)多表查询

    MySQL多表查询 一 使用SELECT子句进行多表查询 SELECT 字段名 FROM 表1,表2 - WHERE 表1.字段 = 表2.字段 AND 其它查询条件 SELECT a.id,a.na ...

  6. R12.2. Start and Stop Procedure

    R12.2. Start and Stop Procedure   Leave a comment Individual Components:  Application(Middle Tier) $ ...

  7. JS跨域请求

    前提:两个项目,第一个项目想请求第二个项目不通过服务器代码只通过页面请求. 1. 第一个项目html(需要第二个项目配合实现) 1 2 3 4 5 6 7 <script> functio ...

  8. DB Query Analyzer 6.03, the most excellent Universal DB Access tools on any Microsoft Windows OS

      DB Query Analyzer 6.03, the most excellent Universal database Access tools on any Microsoft Wind ...

  9. Struts2技术内幕 读书笔记三 表示层的困惑

    表示层能有什么疑惑?很简单,我们暂时忘记所有的框架,就写一个注册的servlet来看看. index.jsp <form id="form1" name="form ...

  10. 在Windows使用git工具将代码同步至github(作者:ying1989920)

     [ps]git是一个分布式代码管理工具,类似于svn,方便协同开发,git里面有所谓的仓库(用来存放代码的),分为本地和线上,线上的你可以自己搭建,不想搭建的话github就给你提供了. [关于 ...