构建ASP.NET MVC5+EF6+EasyUI 1.4.3+Unity4.x注入的后台管理系统(66)-MVC WebApi 用户验证 (2)

 

前言:

回顾上一节,我们利用webapi简单的登录并进行了同域访问与跨域访问来获得Token,您可以跳转到上一节下载代码来一起动手。

继续上一篇的文章,我们接下来演示利用拿到的Token来访问接口,管理接口,利用系统权限管理接口,对每个接口进行授权(管理接口为选读部分,因为你需要阅读最开始权限管理部分(18-27节),才能阅读这部分)

开发环境:

VS2015+无数据库(模拟数据)

样例代码下载   访问密码 8ca3

知识点:

  1. WebApi权限验证
  2. 应用到实际中来
  3. 调试

开始:

1.过滤器验证

  我们之前也是通过过滤器来验证对于Action的操作权限,接口也不例外,在Action切入,在每次访问的时候都附带Token信息,也许你可以通过下列在Http请求头中来附加Token

添加过滤类:SupportFilter并继承AuthorizeAttribute权限筛选器OnAuthorization基类方法

using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Security; namespace Apps.WebApi.Core
{
public class SupportFilter : AuthorizeAttribute
{
//重写基类的验证方式,加入我们自定义的Ticket验证
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
//url获取token
var content = actionContext.Request.Properties["MS_HttpContext"] as HttpContextBase;
var token = content.Request.QueryString["Token"];
if (!string.IsNullOrEmpty(token))
{
//解密用户ticket,并校验用户名密码是否匹配
if (ValidateTicket(token))
{
base.IsAuthorized(actionContext);
}
else
{
HandleUnauthorizedRequest(actionContext);
}
}
//如果取不到身份验证信息,并且不允许匿名访问,则返回未验证401
else
{
var attributes = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().OfType<AllowAnonymousAttribute>();
bool isAnonymous = attributes.Any(a => a is AllowAnonymousAttribute);
if (isAnonymous) base.OnAuthorization(actionContext);
else HandleUnauthorizedRequest(actionContext);
}
} //校验用户名密码(对Session匹配,或数据库数据匹配)
private bool ValidateTicket(string encryptToken)
{
//解密Ticket
var strTicket = FormsAuthentication.Decrypt(encryptToken).UserData; //从Ticket里面获取用户名和密码
var index = strTicket.IndexOf("&");
string userName = strTicket.Substring(0, index);
string password = strTicket.Substring(index + 1);
//取得session,不通过说明用户退出,或者session已经过期
var token = HttpContext.Current.Session[userName];
if (token == null)
{
return false;
}
//对比session中的令牌
if (token.ToString() == encryptToken)
{
return true;
} return false; }
}
}

HttpActionContext是无法取到URL的参数的,需要转换为HttpContextBase,这个类我都有注释,很容易看懂。

1.从URL取到Token,利用之前加密的方式来揭秘Token并得出Token中的用户名

2.利用用户名获取Session中的Token

3.ValidateTicket验证,判断Session中的Token是否与获取到的相同?

2.应用到实际当中来

最后对每个Action进行注解,好在调用接口的时候优先判断是否有权限访问

3.运行调试

  调试之前,我们需要写点代码来访问

修改Home Index代码

<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<style>html,body{height:100%}.box{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#6699FF', endColorstr='#6699FF');background-image:linear-gradient(bottom,#69F 0,#69F 100%);background-image:-o-linear-gradient(bottom,#69F 0,#69F 100%);background-image:-moz-linear-gradient(bottom,#69F 0,#69F 100%);background-image:-webkit-linear-gradient(bottom,#69F 0,#69F 100%);background-image:-ms-linear-gradient(bottom,#69F 0,#69F 100%);margin:0 auto;position:relative;width:100%;height:100%}.login-box{width:100%;max-width:500px;height:400px;position:absolute;top:50%;margin-top:-200px}@@media screen and (min-width:500px){.login-box{left:50%;margin-left:-250px}}.form{width:100%;max-width:500px;height:275px;margin:25px auto 0 auto;padding-top:25px}.login-content{height:300px;width:100%;max-width:500px; padding: 0px; color: rgb(128, 0, 128); line-height: 1.5 !important;">255,250,2550,.6);float:left}.input-group{margin:0 0 30px 0!important}.form-control,.input-group{height:40px}.form-group{margin-bottom:0!important}.login-title{padding:20px 10px; padding: 0px; color: rgb(128, 0, 128); line-height: 1.5 !important;">0,0,0,.6)}.login-title h1{margin-top:10px!important}.login-title small{color:#fff}.link p{line-height:20px;margin-top:30px}.btn-sm{padding:8px 24px!important;font-size:16px!important}
</style> <div class="box" style="margin:100px;height:400px;width:500px;">
<div class="login-box">
<div class="login-title text-center">
<h1><small>登录</small></h1>
</div>
<div class="login-content ">
<div class="form">
<form action="#" method="post">
<div class="form-group">
<div class="col-xs-12 ">
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
<input type="text" id="username" name="username" class="form-control" placeholder="用户名">
</div>
</div>
</div>
<div class="form-group">
<div class="col-xs-12 ">
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span>
<input type="text" id="password" name="password" class="form-control" placeholder="密码">
</div>
</div>
</div>
<div class="form-group form-actions">
<div class="col-xs-4 col-xs-offset-4 ">
<button type="button" id="Login" class="btn btn-sm btn-info"><span class="glyphicon glyphicon-off"></span> 登录</button>
</div>
</div> </form>
</div>
</div>
</div>
</div>
Token:<div id="myToken"></div>
<input type="button" id="getData" value="获取API Get/{id}的值" />
利用Token后获得的值:<div id="myVal"></div>
<script>
$(function () {
$("#Login").click(function () {
$.ajax({
type: "get",
url: "/api/Account/Login",
data: { userName: $("#username").val(), password: $("#password").val() },
success: function (data, status) {
if (data.type==0) {
alert("登录失败");
return;
}
alert("登录成功:Token" + data.message);
$("#myToken").html(data.message);
},
error: function (e) {
alert("登录失败!");
},
complete: function () { }
});
});
$("#getData").click(function () {
$.ajax({
type: "get",
url: "/api/Values/Get/5?Token=" + $("#myToken").html(),
success: function (data, status) {
alert(data);
},
error: function (e) {
alert("失败!");
},
complete: function () { }
});
});
});
</script>

添加一个按钮和DIV好显示结果:

我们获得了正确的数据。如果没有token,我们的结果将会返回一个401

大家可以下载代码把断点设置在

可以调试程序对于Token处理的顺序!

总结:

本节讲解了如何利用Token在来访问需要授权的接口!利用到了MVC的过滤器,在调用Action时候优先进行权限校验,这样就完成了对用户进行接口授权的样例。

以上部分一般都够用了,如果你(ˇˍˇ) 想~更加深入和细微的粒度授权,那么就要对每个接口进行单独授权

如果你有兴趣,那可以继续阅读下面的对API的管理授权

--------------------------------------------------------------------------------------------------------丑陋的分割线-----------------------------------------------------------------------------------------

下面将演示如何管理接口,这需要你之前有跟读本系列的18-27节权限才能阅读!因为大部门利用了之前的管理界面的功能和代码,是紧密联系的,不过没有关系,就算你没有学习之前的系列文章,也许也能从本节中获得知识!

知识点:

  1.取所有类库中的Api接口

  2.管理接口

  3.对接口进行授权

  4.在过滤器添加权限验证

开始:

回顾一下我们的模块管理:

管理的是每一个控制器中的Action(操作码)

我们的WebApi也是如此,每个控制器的操作码,在WebApi运行时候把数据填充到SysModule表和SysModuleOperation表中中来

1.取得类库中所有Api接口

这个真的好用,取得的接口,你平时可以用于管理或自动测试接口

  //把控制器当成URL,把Aciton当成操作码插入到数据表做为权限设置,类似之前的权限系统
//获得API管理器
Collection<ApiDescription> apiColl = GlobalConfiguration.Configuration.Services.GetApiExplorer().ApiDescriptions;
ILookup<HttpControllerDescriptor, ApiDescription> apiGroups = apiColl.ToLookup(api => api.ActionDescriptor.ControllerDescriptor); foreach (var group in apiGroups)
{
//-----------插入Action
foreach (var m in group)
{ }
}

第一个foreach取得控制器,第二个foreach取得控制器下面的Action。大家把这句话添加到Home的Index中来,跟踪一下,分别可以看到Group和m中模型的属性。

现在知道怎么加表了吧!

            foreach (var group in apiGroups)
{ string controllerName = group.Key.ControllerName;
//----------插入控制器
rootModel = m_BLL.GetById(controllerName);
if (rootModel == null)
{
SysModuleModel model = new SysModuleModel()
{
Id = controllerName,
Name = controllerName,
EnglishName = "",
ParentId = "ApiInterfaceAuth",
Url = "api/"+ controllerName,
Iconic = "fa fa-television",
Enable = true,
Remark = "Api接口授权",
Sort = 1,
CreatePerson = "Admin",
CreateTime = DateTime.Now,
IsLast = true
};
m_BLL.Create(ref errors, model);
}
//-----------插入Action
foreach (var m in group)
{
string actionName = m.ActionDescriptor.ActionName;
SysModuleOperateModel model = operateBLL.GetById(m.ActionDescriptor.ActionName);
if (model == null)
{
model = new SysModuleOperateModel();
model.Id = controllerName + actionName;
model.Name = m.Documentation == null ? actionName : m.Documentation;
model.KeyCode = actionName;
model.ModuleId = controllerName;
model.IsValid = true;
model.Sort = 0;
operateBLL.Create(ref errors, model);
} }
}

运行之后数据库将自动添加,几条数据

2.管理接口

表数据跟我们普通的是没有区别的,在界面想办法做个开关做为切换,我这里做了个下拉来切换类型

切换下拉时候,改变查询条件

 <div style="float:left">
菜单类型切换: <select class="easyui-combobox" name="swicthType" id="swicthType" style="width:80px;height:26px;margin-right:10px; ">
<option value="menu">系统菜单</option>
<option value="api">Api接口</option>
</select>
</div>
$('#swicthType').combobox({
editable: false,
onSelect: function (record) {
if (record.value == "api") {
$('#List').treegrid({"url":'@Url.Action("GetList")?id=ApiInterfaceAuth'});
$('#OptList').datagrid('loadData', { total: 0, rows: [] });
} else {
$('#List').treegrid({"url":'@Url.Action("GetList")?id=0'});
$('#OptList').datagrid('loadData', { total: 0, rows: [] });
} }
});

3.对接口进行授权

授权后可以查询到:

为了更好的区分,我将只给超级管理员Get接口的权限

4.在过滤器中添加验证

这时候我们需要复制之前系统中过滤器的验证代码过来使用,并稍作修改为下面代码:

public class SupportFilter : AuthorizeAttribute
{
//重写基类的验证方式,加入我们自定义的Ticket验证
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
//url获取token
var content = actionContext.Request.Properties[ConfigPara.MS_HttpContext] as HttpContextBase; var token = content.Request.QueryString[ConfigPara.Token];
if (!string.IsNullOrEmpty(token))
{
//解密用户ticket,并校验用户名密码是否匹配 //读取请求上下文中的Controller,Action,Id
var routes = new RouteCollection();
RouteConfig.RegisterRoutes(routes);
RouteData routeData = routes.GetRouteData(content);
//取出区域的控制器Action,id
string controller = actionContext.ActionDescriptor.ControllerDescriptor.ControllerName;
string action = actionContext.ActionDescriptor.ActionName;
//URL路径
string filePath = HttpContext.Current.Request.FilePath;
if (LoginUserManage.ValidateTicket(token) && ValiddatePermission(token, controller, action, filePath))
{
//已经登录,有权限,且没有单机登录限制
base.IsAuthorized(actionContext);
}
else
{
HandleUnauthorizedRequest(actionContext);
}
}
//如果取不到身份验证信息,并且不允许匿名访问,则返回未验证401
else
{
var attributes = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().OfType<AllowAnonymousAttribute>();
bool isAnonymous = attributes.Any(a => a is AllowAnonymousAttribute);
if (isAnonymous) base.OnAuthorization(actionContext);
else HandleUnauthorizedRequest(actionContext);
}
}
public bool ValiddatePermission(string token, string controller, string action, string filePath)
{
bool bResult = false; List<permModel> perm = null; perm = (List<permModel>)HttpContext.Current.Session[filePath];
if (perm == null)
{
SysUserBLL userBLL = new SysUserBLL()
{
m_Rep = new SysUserRepository(new DBContainer()),
sysRightRep = new SysRightRepository(new DBContainer())
};
{
var userName = LoginUserManage.DecryptToken(token.Trim());
perm = userBLL.GetPermission(userName, controller);//获取当前用户的权限列表
HttpContext.Current.Session[filePath] = perm;//获取的劝降放入会话由Controller调用
}
//查询当前Action 是否有操作权限,大于0表示有,否则没有
int count = perm.Where(a => a.KeyCode.ToLower() == action.ToLower()).Count();
if (count > 0)
{
bResult = true;
}
else
{
bResult = false;
LoginUserManage.RedirectUrl();
}
}
return bResult;
}
}

这样,访问时候将对当前访问的控制器和Action进行权限校验,没有权限同样返回401

接下来写两个方法测试一下,一个访问Values的Get方法,一个访问Values的Post

<script>
$(function () {
$("#Login").click(function () {
$.ajax({
type: "get",
url: "/api/Account/Login",
data: { userName: $("#username").val(), password: $("#password").val() },
success: function (data, status) {
if (data.type==0) {
alert("登录失败");
return;
}
alert("登录成功:Token" + data.message);
$("#myToken").html(data.message);
},
error: function (e) {
alert("登录失败!");
},
complete: function () { }
});
});
$("#getData").click(function () {
$.ajax({
type: "get",
url: "/api/Values/Get/5?Token=" + $("#myToken").html(),
success: function (data, status) {
alert(data);
},
error: function (e) {
alert("失败!");
},
complete: function () { }
});
});
$("#postData").click(function () {
$.ajax({
type: "post",
url: "/api/Values/Post?Token=" + $("#myToken").html(),
data:{value:"123"},
success: function (data, status) {
alert(data);
},
error: function (e) {
alert(e);
},
complete: function () { }
});
});
});
</script>

总结:

  其实基于WebApi的权限他们也是如此设计的,您可以集成到你现有的权限系统来

  感谢你抽时间看完本节,所谓 赞 得高尿得远,嘿嘿...

作者:YmNets
出处:http://ymnets.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

MVC WebApi 用户验证 (2)的更多相关文章

  1. 构建ASP.NET MVC5+EF6+EasyUI 1.4.3+Unity4.x注入的后台管理系统(66)-MVC WebApi 用户验证 (2)

    前言: 构建ASP.NET MVC5+EF6+EasyUI 1.4.3+Unity4.x注入的后台管理系统(65)-MVC WebApi 用户验证 (1) 回顾上一节,我们利用webapi简单的登录并 ...

  2. ASP.NET MVC5+EF6+EasyUI 后台管理系统(66)-MVC WebApi 用户验证 (2)

    系列目录 前言: 回顾上一节,我们利用webapi简单的登录并进行了同域访问与跨域访问来获得Token,您可以跳转到上一节下载代码来一起动手. 继续上一篇的文章,我们接下来演示利用拿到的Token来访 ...

  3. ASP.NET MVC5+EF6+EasyUI 后台管理系统(65)-MVC WebApi 用户验证 (1)

    系列目录 前言: WebAPI主要开放数据给手机APP,其他需要得知数据的系统,或者软件应用,所以移动端与系统的数据源往往是相通的. Web 用户的身份验证,及页面操作权限验证是B/S系统的基础功能, ...

  4. MVC全局用户验证之HttpModule

    在请求进入到MVC的处理mcvHandler之前,请求先到达HttpModule,因此可以利用HttpModule做全局的用户验证. HttpModule MVC5之前的版本基于system.web. ...

  5. ASP.NET MVC 5 WEB API 用户验证

    参考博客:ASP.NET MVC5+EF6+EasyUI 后台管理系统(65)-MVC WebApi 用户验证 (1) 参考博客:MVC WebApi 用户验证 (2)构建ASP.NET MVC5+E ...

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

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

  7. ASP.NET MVC WebApi接口授权验证

    对于很任何多开发者来说,不管是使用任何一种框架,或者是使用任何一种语言,都要使用面向接口编程.使用面向接口编程的时候,那么就会有很多的权限验证,用户验证等等. 特别是对于一些系统来说,别人想要对接你的 ...

  8. WebApi用户登录验证及服务器端用户状态存取

    最近项目需要给手机端提供数据,采用WebApi的方式,之前的权限验证设计不是很好,这次采用的是Basic基础认证. 1.常见的认证方式 我们知道,asp.net的认证机制有很多种.对于WebApi也不 ...

  9. .net MVC使用Session验证用户登录(转载)

    .net MVC使用Session验证用户登录   用最简单的Session方式记录用户登录状态 1.添加DefaultController控制器,重写OnActionExecuting方法,每次访问 ...

随机推荐

  1. 摆方块(贪心)P1087

    描述 给你一个n*n的方格,每个方格里的数必须连续摆放如 1      2 4      3 ,下图为不连续的,请输出从左上角到右下角的对角线上的最大和 1       2 3       4 输入 ...

  2. bzoj1864 [Zjoi2006]三色二叉树

    Description Input 仅有一行,不超过500000个字符,表示一个二叉树序列. Output 输出文件也只有一行,包含两个数,依次表示最多和最少有多少个点能够被染成绿色. Sample ...

  3. 图的深度优先遍历DFS

    图的深度优先遍历是树的前序遍历的应用,其实就是一个递归的过程,我们人为的规定一种条件,或者说一种继续遍历下去的判断条件,只要满足我们定义的这种条件,我们就遍历下去,当然,走过的节点必须记录下来,当条件 ...

  4. tangible T4 Editor 2.2.3 plus modeling tools for VS 2012 扩展名

    tangible T4 Editor 2.2.3 plus modeling tools for VS 2012 扩展名 tangible T4 Editor 2.2.3 plus modeling ...

  5. 51操作各种demo 驱动

    24C02 bit write=0; //写24C02的标志: sbit sda=P2^0; sbit scl=P2^1; void delay0() { ;; } void start() //开始 ...

  6. 【转】Linux内核调试方法总结

    目录[-] 一  调试前的准备 二  内核中的bug 三  内核调试配置选项 1  内核配置 2  调试原子操作 四  引发bug并打印信息 1  BUG()和BUG_ON() 2  dump_sta ...

  7. 【转】android电池(五):电池 充电IC(PM2301)驱动分析篇

    关键词:android 电池  电量计  PL2301任务初始化宏 power_supply 中断线程化 平台信息:内核:linux2.6/linux3.0系统:android/android4.0  ...

  8. LightOJ 1338 && 1387 - Setu && LightOJ 1433 && CodeForces 246B(水题)

    B - B Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu Submit Status P ...

  9. [Python] 发送email的几种方式

    python发送email还是比較简单的,能够通过登录邮件服务来发送,linux下也能够使用调用sendmail命令来发送,还能够使用本地或者是远程的smtp服务来发送邮件,无论是单个,群发,还是抄送 ...

  10. Object-c学习之路九(字典(NSDictionary&NSMutableDictionary))

    字典的练习和使用(遍历,搜索...)(Student和Book类文件可以查看上篇博客这次不上传了.) // // main.m // NSDictionary // // Created by Wil ...