ASP.NET MVC5+EF6+EasyUI 后台管理系统(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;background-color:rgba(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;background-color:rgba(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://www.cnblogs.com/ymnets/p/5721137.html,如需转载请自行联系原作者

相关文章
|
6月前
|
开发框架 Oracle 关系型数据库
ASP.NET实验室LIS系统源码 Oracle数据库
LIS是HIS的一个组成部分,通过与HIS的无缝连接可以共享HIS中的信息资源,使检验科能与门诊部、住院部、财务科和临床科室等全院各部门之间协同工作。 
75 4
|
5月前
基于EasyUI的后台管理系统页面原型_示例图_下载地址
基于EasyUI的后台管理系统页面原型_示例图_下载地址
34 0
|
3月前
|
开发框架 前端开发 .NET
ASP.NET MVC WebApi 接口返回 JOSN 日期格式化 date format
ASP.NET MVC WebApi 接口返回 JOSN 日期格式化 date format
46 0
|
3月前
|
开发框架 NoSQL .NET
使用 Asp.net core webapi 集成配置系统,提高程序的灵活和可维护性
使用 Asp.net core webapi 集成配置系统,提高程序的灵活和可维护性
|
5月前
|
开发框架 前端开发 .NET
LIMS(实验室)信息管理系统源码、有哪些应用领域?采用C# ASP.NET dotnet 3.5 开发的一套实验室信息系统源码
集成于VS 2019,EXT.NET前端和ASP.NET后端,搭配MSSQL 2018数据库。系统覆盖样品管理、数据分析、报表和项目管理等实验室全流程。应用广泛,包括生产质检(如石化、制药)、环保监测、试验研究等领域。随着技术发展,现代LIMS还融合了临床、电子实验室笔记本和SaaS等功能,以满足复杂多样的实验室管理需求。
80 3
LIMS(实验室)信息管理系统源码、有哪些应用领域?采用C# ASP.NET dotnet 3.5 开发的一套实验室信息系统源码
|
5月前
|
Web App开发 开发框架 .NET
ASP淘特二手房房地产系统源码
ASP淘特二手房房地产系统源码主要提供了房屋信息出售、出租、求购、求租、合租等信息的发布平台。 本系统已提供成熟的赢利模式,通过向中介会员提供发布信息平台收取会员费为网站的主要收入来源,中介会员申请开通后,可以添加经济人和管理中介公司所属的房源信息。可在线续费购买服务期(支付宝接口)、购买置顶等。
63 2
|
6月前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
189 0
|
4月前
|
开发框架 JSON .NET
|
5月前
|
JSON 开发框架 前端开发
技术经验分享:ASP.NETCoreMVC打造一个简单的图书馆管理系统(修正版)(七)学生信息增删
技术经验分享:ASP.NETCoreMVC打造一个简单的图书馆管理系统(修正版)(七)学生信息增删
31 0
|
6月前
|
开发框架 前端开发 JavaScript
JavaScript云LIS系统源码ASP.NET CORE 3.1 MVC + SQLserver + Redis医院实验室信息系统源码 医院云LIS系统源码
实验室信息系统(Laboratory Information System,缩写LIS)是一类用来处理实验室过程信息的软件,云LIS系统围绕临床,云LIS系统将与云HIS系统建立起高度的业务整合,以体现“以病人为中心”的设计理念,优化就诊流程,方便患者就医。
78 0