ASP.NET MVC5+EF6+EasyUI 后台管理系统(66)-MVC WebApi 用户验证 (2)
系列目录
前言:
回顾上一节,我们利用webapi简单的登录并进行了同域访问与跨域访问来获得Token,您可以跳转到上一节下载代码来一起动手。
继续上一篇的文章,我们接下来演示利用拿到的Token来访问接口,管理接口,利用系统权限管理接口,对每个接口进行授权(管理接口为选读部分,因为你需要阅读最开始权限管理部分(18-27节),才能阅读这部分)
开发环境:
VS2015+无数据库(模拟数据)
样例代码下载 访问密码 8ca3
知识点:
- WebApi权限验证
- 应用到实际中来
- 调试
开始:
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(, index);
string password = strTicket.Substring(index + );
//取得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:%}.box{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#6699FF', endColorstr='#6699FF');background-image:linear-gradient(bottom,#69F ,#69F %);background-image:-o-linear-gradient(bottom,#69F ,#69F %);background-image:-moz-linear-gradient(bottom,#69F ,#69F %);background-image:-webkit-linear-gradient(bottom,#69F ,#69F %);background-image:-ms-linear-gradient(bottom,#69F ,#69F %);margin: auto;position:relative;width:%;height:%}.login-box{width:%;max-width:500px;height:400px;position:absolute;top:%;margin-top:-200px}@@media screen and (min-width:500px){.login-box{left:%;margin-left:-250px}}.form{width:%;max-width:500px;height:275px;margin:25px auto auto;padding-top:25px}.login-content{height:300px;width:%;max-width:500px;background-color:rgba(,,,.);float:left}.input-group{margin: 30px !important}.form-control,.input-group{height:40px}.form-group{margin-bottom:!important}.login-title{padding:20px 10px;background-color:rgba(,,,.)}.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==) {
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 = ,
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 = ;
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: , rows: [] });
} else {
$('#List').treegrid({"url":'@Url.Action("GetList")?id=0'});
$('#OptList').datagrid('loadData', { total: , 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 > )
{
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==) {
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:""},
success: function (data, status) {
alert(data);
},
error: function (e) {
alert(e);
},
complete: function () { }
});
});
});
</script>
总结:
其实基于WebApi的权限他们也是如此设计的,您可以集成到你现有的权限系统来
感谢你抽时间看完本节,所谓 赞 得高尿得远,嘿嘿...
ASP.NET MVC5+EF6+EasyUI 后台管理系统(66)-MVC WebApi 用户验证 (2)的更多相关文章
- ASP.NET MVC5+EF6+EasyUI 后台管理系统-分配角色给用户
系列目录 由于之前做了将权限赋给角色,还需要做将角色组赋给用户,和将用户赋给角色组,一个用户可以拥有多个角色组,一个角色组包含多个用户,打开模块管理,添加一个分配的操作码 并在 角色权限设置授权给他 ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-前言与目录(持续更新中...)
开发工具:VS2015(2012以上)+SQL2008R2以上数据库 您可以有偿获取一份最新源码联系QQ:729994997 价格 666RMB 升级后界面效果如下: 任务调度系统界面 http: ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-前言与目录(转)
开发工具:VS2015(2012以上)+SQL2008R2以上数据库 您可以有偿获取一份最新源码联系QQ:729994997 价格 666RMB 升级后界面效果如下: 日程管理 http://ww ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(63)-Excel导入和导出-自定义表模导入
系列目录 前言 上一节使用了LinqToExcel和CloseXML对Excel表进行导入和导出的简单操作,大家可以跳转到上一节查看: ASP.NET MVC5+EF6+EasyUI 后台管理系统(6 ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统-WebApi的用法与调试
1:ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-WebApi与Unity注入 使用Unity是为了使用我们后台的BLL和DAL层 2:ASP.NET MVC5+EF6+Easy ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(51)-系统升级
系统很久没有更新内容了,期待已久的更新在今天发布了,最近花了2个月的时间每天一点点,从原有系统 MVC4+EF5+UNITY2.X+Quartz 2.0+easyui 1.3.4无缝接入 MVC5+E ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(58)-DAL层重构
系列目录 前言:这是对本文系统一次重要的革新,很久就想要重构数据访问层了,数据访问层重复代码太多.主要集中增删该查每个模块都有,所以本次是为封装相同接口方法 如果你想了解怎么重构普通的接口DAL层请查 ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(34)-文章发布系统①-简要分析
系列目录 最新比较闲,为了学习下Android的开发构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(1)-前言与,虽然有点没有目的的学习,但还是了解了Andro ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(54)-工作流设计-所有流程监控
系列目录 先补充一个平面化登陆页面代码,自己更换喜欢的颜色背景 @using Apps.Common; @{ Layout = null; } <!DOCTYPE html> <ht ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(56)-插件---单文件上传与easyui使用fancybox
系列目录 https://yunpan.cn/cZVeSJ33XSHKZ 访问密码 0fc2 今天整合lightbox插件Fancybox1.3.4,发现1.3.4版本太老了.而目前easyui 1 ...
随机推荐
- 【AR实验室】mulberryAR : ORBSLAM2+VVSION
本文转载请注明出处 —— polobymulberry-博客园 0x00 - 前言 mulberryAR是我业余时间弄的一个AR引擎,目前主要支持单目视觉SLAM+3D渲染,并且支持iOS端,但是该引 ...
- 透过WinDBG的视角看String
摘要 : 最近在博客园里面看到有人在讨论 C# String的一些特性. 大部分情况下是从CODING的角度来讨论String. 本人觉得非常好奇, 在运行时态, String是如何与这些特性联系上的 ...
- 0-1背包问题蛮力法求解(java版本)
sloves: package BackPack; public class Solves { public int[] DecimaltoBinary(int n,int m) { int ...
- 【java】Naming.bind和Registry.bind区别
Naming类和Registry类均在java.rmi包 Naming类通过解析URI绑定远程对象,将URI拆分成主机.端口和远程对象名称,使用的仍是Registry类. public static ...
- 8、Struts2 运行流程分析
1.流程分析: 请求发送给 StrutsPrepareAndExecuteFilter StrutsPrepareAndExecuteFilter 询问 ActionMapper: 该请求是否是一个 ...
- C#中将DataTable导出为HTML的方法
今天我要向大家分享一种将DataTable导出为到HTML格式的方法.有时我们需要HTML格式的输出数据, 以下代码就可以帮助我们达到目的,. 首先,我们要绑定DataTable和 DataGridV ...
- Android中的沉浸式状态栏效果
无意间了解到沉浸式状态栏,感觉贼拉的高大上,于是就是试着去了解一下,就有了这篇文章.下面就来了解一下啥叫沉浸式状态栏.传统的手机状态栏是呈现出黑色条状的,有的和手机主界面有很明显的区别.这一样就在一定 ...
- 信息安全-2:python之hill密码算法[原创]
转发注明出处:http://www.cnblogs.com/0zcl/p/6106513.html 前言: hill密码算法我打算简要介绍就好,加密矩阵我用教材上的3*3矩阵,只做了加密,解密没有做, ...
- 超详细mysql left join,right join,inner join用法分析
下面是例子分析表A记录如下: aID aNum 1 a20050111 2 a20050112 3 a20050113 4 ...
- NV显卡Ubuntu14.04更新软件导致登录死循环,不过可以进入tty模式
注意:此方法只适用于nv显卡的电脑! 在网上寻找各种方法无果的情况下,选择重新安装显卡驱动,成功登录进入图形界面. 一.首先需要在另外一台电脑(windows系统也可以)上下载NVIDIA相应显卡驱动 ...