• HTML+LayUI+WebApi 简单个人小白demo教程 ----《.Net踩坑之路(二)》


    题外话:

    接上篇吧。上篇主要是介绍下LayUI的使用,太兴奋手打代码去了- -。

    其实这个项目用了Unity这个IOC框架,毕竟人要有梦想。感兴趣的可以自己去了解下,后面有机会会说说对于IOC和DI的个人拙见以及Unity的使用。

    进入正题。


    二.WebApi

    一个有梦想的咸鱼做的一个有梦想的demo项目就需要有梦想的考虑后期维护与扩展,那么就需要从建项目开始做好文件分类。

    打开VS,选择ASP .NET Web应用程序(.NET Framework)创建一个新的项目命名Demo,然后选择Web Api,然后建立项目。注意看项目下有个Area的文件夹,作用呢其实就是可以区分控制器,方便管理,而且控制器名称可以重名。

    毕竟是个B/S项目,后台所接收的请求都属于http请求,要处理这些请求后台,就会涉及到安全问题,也就是权限问题,毕竟要有梦想,还是可以发布上服务器的。而这个安全问题并不是只用用户登录验证就能解决的,这时候就会涉及到权限问题,参考淘宝,你可以随意浏览,但是一些额外操作则需要登录。

    所以这里我是考虑FormsAuthenticationTicket身份验证配合授权属性AuthorizeAttribute。

    Ticket,顾名思义,想入场看比赛是需要门票的,那么想进入自己的网站或者有数据库操作时,我们可以为用户设置门票。

    进而小朋友些许问号,演唱会门票还有前排后排区别,考虑到实际应用情况,我们是否也需要对于用户进行权限区分,这样比较符合实际情况?这样是否更灵活?用户与角色都能去控制

    Controller的权限是否更科学?没错,尤其是MVC项目,但是这里先不考虑这么多,我们后台只提供接口服务。这里我只是提供一个思路,因为要做一个大度的人,只要人进得来,场地自由活动好吧。(就是懒~)

    所以会需要使用到授权属性AuthorizeAttribute类。

    • AuthorizeAttribute

    AuthorizeAttribute类是.Net Framework框架下提供写好的一个类,Authorization(授权)属于过滤器的一种。

    这里可以提下当引用AuthorizeAttribute类时方法的执行过程。当给某一个 Controller 指定一个权限认证特性后,当程序需要调用这个Controller时,会先进入namespace为System.Web.Http的AuthorizeAttribute公共类,而后首先会执行AuthorizeAttribute 中的 OnAuthorization 方法,在 OnAuthorization 函数的执行过程中,如果验证失败了,系统会调用 HandleUnauthorizedRequest方法来进行处理,基于此原理,我们可以重写这两个方法,然后自定义自己的AuthorizeAttribute。而如果想提供匿名访问服务,即调用Controller时不进入AuthorizeAttribute,它提供了AllowAnonymousAttribute属性,字面意思也知道。

    基于上述的执行过程,既然是虚函数,我们重写他的两个主要方法。

    首先,新建文件夹Filter,文件夹下新建一个继承于AuthorizeAttribute的类,以XXAuthorizeAttribute命名,XX则就是自定义的特性名称。我这里是ApiAuthorizeAttribute。

     首先重写OnAuthorization(HttpActionContext actionContext)。

        /// <summary>
        /// api权限特性
        /// </summary>
        [AttributeUsage(AttributeTargets.Class|AttributeTargets.Method)]
        public class ApiAuthorizeAttribute : AuthorizeAttribute
        {
            public override void OnAuthorization(HttpActionContext actionContext)
            {
                var authorization = actionContext.Request.Headers.Authorization;
    
                if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>(true).Count != 0
                    || actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>(true).Count != 0)
                {
                    base.OnAuthorization(actionContext);//正确的访问方法
                }
                else
                {
                    if (authorization != null && authorization.Parameter != null)
                    {this.HandleUnauthorizedRequest(actionContext);//没有权限
                    }
                    else
                    {
                        this.HandleUnauthorizedRequest(actionContext);//没有权限
                    }
                }
            }
    
            protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
            {
                base.HandleUnauthorizedRequest(actionContext);
            }
        }

    梳理下逻辑:

    首先,通过HttpActionContext 获得我们在ajax中传入的Requset.Headers.Authorization.

    然后,通过判断是否有AllowAnonymousAttribute标识。

    结合实际场景来理解这一步,还是上文例子。我总不可能一个演唱会主角还没进场就给保安拦着了要我出示票据???我自己唱歌难道还要自己出钱买票欸?好气哦是不是?

    是的,如果你是保安你就被喷了,那一样的,如果你是这个项目的开发者,整个项目运行起来就没一个人能登录进来,连你自己都进不去,所以考虑实际开发不要反人类逻辑思考,那么就提供了AllowAnonymousAttribute。通过在控制器上加上[AllowAnonymous],相当于走绿色通道不要门票,那么这个最应该放在哪呢?

    如果没有关系走不了后门,那么就老实判断有无门票。

    然后如果没有,保安赶人,也就是进入HandleUnauthorizedRequest方法,这是会直接将页面重定向到登录页面。当然你要是宅心仁厚是个文化人,不想要保安如此粗鲁,自己重写代码

    返回一段现在最流行的Json数据问问施主可还有其他诉求。

    这里就会涉及到一个问题,WebApi的返回值是不支持的Json格式的,如果又不想更改配置,那么可以利用HttpResponseMessage返回Json。

    return new HttpResponseMessage()
                {
                    Content = new StringContent("string", Encoding.UTF8, "application/json"),
                };

     这一步做完,是不是觉得终于可以进行激动人心的登录仪式了?

    想什么呢,什么都没有。数据库你都没有呢朋友。建库建表都还没进行呢。

    • ORM
    • Entity Framework

    Object Relational Mapping,对象关系映射。

    这个内容很多,这里使用Entity Framework,毕竟.Net一套。至于为什么,最直接的就是因为不想写SQL语句而且安全,这理由还不充分吗?不行你往你自己用SQL语句写的登录网站试试输入' or 1 = 1 --',看看会不会有惊喜?有惊喜的少年恭喜你真的很适合看我的博客,给个关注给个推荐谢谢嗷。

    下个定义:EF是微软基于ADO .Net而开发的一套跨数据库的ORM框架(hhhhhh这里就不做过多赘述了,资料很多,我自己也写了一个Word文档,如果全小白自学的可以联系我发给你哈哈哈,其实后面会单独写EF的,还会浅谈下自学的Entity Framework Core,毕竟我也很菜)

    在解决方案Demo下建立Data文件夹,文件夹下新建一个.Net Frameworek的类库,取名Domain,Domain类库下建立Models文件夹,此文件夹下建立实体类。

    建库建表时就要考虑到项目需求问题,这点很重要很重要很重要,这也是有无项目经验的主要体现。加粗加红好了。

    因为是个简单教程,那么我这个项目,目前先做个做个能给每个公司提供管理员工,管理自己公司信息报表的简单平台。后期纵向横向发展那些再说。比如加个department表之类的,然后再来个上级管理,下级管理啊啧啧啧,少年自己冲。

    我们先建立简单的三张表,一张员工表,提供账号密码以及简单个人信息问题。一张账号信息表,方便记录一些账号操作行为。一张公司表,提供基础信息。

    公司与员工的关系,员工与账号的关系,设置一个公司有一个管理账号,那么又有管理账号与普通账号的关系,又会有角色区别。

    建表时,考虑到更新性原因,尽量不适用外键,所有依赖关系通过自己去思考,比如账号信息表是不是应该有个用户ID字段,以便于进行联表操作之类,同时对于删除问题,可以根据不同情景,去考虑使用物理删除还是逻辑删除。

    这里简单提下物理删除和逻辑删除的区别:物理删除是删除数据库中的数据,不具有恢复性。而逻辑删除,不删除数据库中的数据,而是通过一些自定义的Flag去判断,可以理解为黑名单,你可以表格中设置bool 类型字段deleteSian,为true时可以使用,为false时拉黑,禁用,当需要时可以解除拉黑。

    EmployeeModel类: 

    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    
    namespace Demo.Domain.Models
    {
        [Table("EmployeesInfo")]
        public class EmployeesInfoModel
        {
            [Key]
            public int EmployeesID { get; set; }
            public int CompanyID { get; set; }
            /// <summary>
            /// 员工姓名
            /// </summary>
            public string Name { get; set; }
            /// <summary>
            /// 性别
            /// </summary>
            public string Sex { get; set; }
            /// <summary>
            /// 工号
            /// </summary>
            public string JobNumber { get; set; }
            /// <summary>
            /// 员工电话
            /// </summary>
            public string Mobile { get; set; }
            /// <summary>
            /// 账号
            /// </summary>
            public string AccountNum { get; set; }
            /// <summary>
            /// 密码
            /// </summary>
            public string PassWords { get; set; }
            /// <summary>
            /// 账号身份
            /// </summary>
            public int AccountRole { get; set; }
            /// <summary>
            /// 员工职位
            /// </summary>
            public int EmployeeRole { get; set; } 
            public bool deleteSign { get; set; }
        }
    }

     AccountInfoModel类:

    using System;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    
    namespace Demo.Domain.Models
    {
        [Table("AccountInfo")]
        public class AccountInfoModel
        {
            [Key]
            public int AccountID { get; set; }
            /// <summary>
            /// 账号名
            /// </summary>
            public string AccountName { get; set; }
            public int EmployeesID { get; set; }
            /// <summary>
            /// 管理查询
            /// </summary>
            public int CompanyID { get; set; }
            /// <summary>
            /// 登陆次数
            /// </summary>
            public int LoginCount { get; set; }
            /// <summary>
            /// 开号时间
            /// </summary>
            public DateTime? CreateTime { get; set; }
            public string CreateIP { get; set; }
            /// <summary>
            /// 最后登陆时间
            /// </summary>
            public DateTime? LastLoginTime { get; set; }
            public string LastLoginIP { get; set; }
        }
    }

    CompanyInfoModel类:

    using System;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    
    namespace Demo.Domain.Models
    {
        [Table("CompanyInfo")]
        public class CompanyInfoModel
        {
            /// <summary>
            /// 编号
            /// </summary>
            [Key]
            public int CompanyID { get; set; }
            /// <summary>
            ////// </summary>
            public string Province { get; set; }
            /// <summary>
            ////// </summary>
            public string City { get; set; }
            /// <summary>
            ////// </summary>
            public string Area { get; set; }
            /// <summary>
            /// 全称
            /// </summary>
            public string FullName { get; set; }
            /// <summary>
            /// 组织机构代码
            /// </summary>
            public string Organizationcode { get; set; }
            
            public string Mobile { get; set; }
    
            public int Power { get; set; }
    
            public bool deleteSign { get; set; }
        }
    
        /// <summary>
        /// 管理范围
        /// </summary>
        //public enum Power
        //{
        //    全部 = 0,
        //    多区 = 1,
        //    单区 = 2
        //}
        ///// <summary>
        ///// 账号身份
        ///// </summary>
        //public enum AccountRole
        //{
        //    管理登录 = 0,
        //    普通登录 = 1
        //}
        ///// <summary>
        ///// 员工身份
        ///// </summary>
        //public enum EmployeeRole
        //{
        //    部门主管 = 0,
        //    普通员工 = 1
        //}
    }

     也可以使用枚举,这里我还是没用了。但是意思就是这么个意思哈哈哈哈。

    通过EF建库建表完成之后,是不是觉得终于可以进行激动人心的登录仪式了?

    对的,没错。

    但是,

    最近忙,饿了,回家做饭。下回分解。逃。

  • 相关阅读:
    HDU 6040 Hints of sd0061 —— 2017 Multi-University Training 1
    HDU 6038 Function —— 2017 Multi-University Training 1
    HDU 6034 Balala Power! —— Multi-University Training 1
    使用python将excel数据导入数据库
    python reload(sys)找不到,name 'reload' is not defined
    伯乐在线资讯URL
    伯乐在线文章URL
    慕课网python分布式爬虫打造搜索引擎视频中爬取伯乐网文章
    javascript HTML DOM 简单介绍
    css样式大全
  • 原文地址:https://www.cnblogs.com/InsufficientLuo/p/InsufficientLuo.html
Copyright © 2020-2023  润新知