zoukankan      html  css  js  c++  java
  • .Net中关于SOA的三大组件之WebApi

      说到WebApi,我想你应该对RESTful也并不陌生,因为你或多或少都听说过RESTful Api。那么什么是RESTful呢?我们一起来看一下。

      RESTful其实是一种架构风格,它体现了表现层的状态转化, 是一个接口的设计风格,它具有以下特点:

    • 资源:万物看成资源,
    • 提供统一接口:CRUD增删改查,将增删改查操作跟HTTP Method对应起来。

        Create => Post,Read => Get,Update => Put/Patch,Delete => Delete

    • URI:统一资源定位符,资源对应的唯一地址
    • 无状态:基于Http协议, (登陆系统--查询工资--计算税收,有状态),无状态的直接一个地址,就能拿到工资,就能得到税收

      我们知道,WebService采用的是http协议和soap协议,只能在IIS承载,入门简单,XML跨平台,而WCF是集大成者,可以采用多种协议,多种宿主,整合了RPC。而WebApi,则采用了RESTful的架构风格,采用http协议,无状态,标准化操作,其更轻量级,尤其是json,特别适合移动端调用。

      那么,WebApi是如何找到我们定义的方法的呢?

      网站在启动时执行Application_Start,然后给路由Routes增加地址规则,当请求进来时,会经过路由匹配找到合适的Controller,然后再去找Action。那怎么找的Action呢?

    • 根据HttpMethod找方法,用的方法名字开头,Get就是对应Get请求
    • 如果名字不是Get开头,可以加上[HttpGet]
    • 按照参数找最吻合

      除了在Application_start为路由添加地址规则意外,还有个特性路由!可以单独订制。需要我们在WebApiConfig中添加 config.MapHttpAttributeRoutes();然后在Controller或Action添加 Route 标记特性。

       上面我们也提到WebApi通常为第三方如App提供接口,那么就应该关注它的权限认证如何实现,下面是基本的认证步骤

    • 登陆过程,拿到令牌--token--ticket--许可证
    • 验证成功--账号+密码+其他信息+时间--加密一下得到ticket---返回给客户端
    • 请求时,request里面带上这个ticket(header)
    • 接口调用时,就去验证ticket,解密一下,看看信息是否合法,看看时间是否过期
    • 每个方法都验证下ticket?显然不合适,可以基于filter来实现,如AuthorizeAttribute

      下面看一下具体的认证代码,登录我们使用表单认证

    public string Login(string account, string password)
    {
        if ("Admin".Equals(account) && "123456".Equals(password))//应该数据库校验
        {
            FormsAuthenticationTicket ticketObject = new FormsAuthenticationTicket(0, account, DateTime.Now, DateTime.Now.AddHours(1), true, string.Format("{0}&{1}", account, password), FormsAuthentication.FormsCookiePath);
            var result = new
            {
                Result = true,
                Ticket = FormsAuthentication.Encrypt(ticketObject)
            };
            return JsonConvert.SerializeObject(result);
        }
        else
        {
            var result = new { Result = false };
            return JsonConvert.SerializeObject(result);
        }
    }
       public class CustomBasicAuthorizeAttribute : AuthorizeAttribute
        {
            /// <summary>
            /// action前会先来这里完成权限校验
            /// </summary>
            /// <param name="actionContext"></param>
            public override void OnAuthorization(HttpActionContext actionContext)
            {
                //actionContext.Request.Headers["Authorization"]
                if (actionContext.ActionDescriptor.GetCustomAttributes<CustomAllowAnonymousAttribute>().FirstOrDefault() != null)
                {
                    return;//继续
                }
                else if (actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<CustomAllowAnonymousAttribute>().FirstOrDefault() != null)
                {
                    return;//继续
                }
                else
                {
                    var authorization = actionContext.Request.Headers.Authorization;
                    if (authorization == null)
                    {
                        this.HandlerUnAuthorization();
                    }
                    else if (this.ValidateTicket(authorization.Parameter))
                    {
                        return;//继续
                    }
                    else
                    {
                        this.HandlerUnAuthorization();
                    }
                }
            }
    
            private void HandlerUnAuthorization()
            {
                throw new HttpResponseException(System.Net.HttpStatusCode.Unauthorized);
            }
            private bool ValidateTicket(string encryptTicket)
            {
                ////解密Ticket
                //if (string.IsNullOrWhiteSpace(encryptTicket))
                //    return false;
                try
                {
                    var strTicket = FormsAuthentication.Decrypt(encryptTicket).UserData;
                    //FormsAuthentication.Decrypt(encryptTicket).
                    return string.Equals(strTicket, string.Format("{0}&{1}", "Admin", "123456"));//应该分拆后去数据库验证
                }
                catch (Exception ex)
                {
                    return false;
                }
    
            }
        }

      然后在需要认证的Controller或Action中添加该特性即可。

      

      WebApi除了为App提供接口,在前后端分离大行其道的现在,WebApi也往往用来为前端提供接口数据,而在前端调用时就会碰到 跨域请求的问题。

      那么什么是跨域请求呢?其是指浏览器请求时,如果A网站(域名+端口)页面里面,通过XHR请求了B域名,就叫做跨域请求。这个请求是可以正常到达B服务器后端,正常的响应(200),但是,浏览器不允许这样操作,除非在响应里面有声明(Access-Control-Allow-Origin)。

      为什么会存在跨域问题呢? 由于浏览器同源策略:处于安全考虑,浏览器限制脚本去发起跨站请求,但是,页面是js/css/图片/iframe 这些是浏览器自己发起的,是可以跨域的 。它的核心就在于它认为自任何站点装载的信赖内容是不安全的。当被浏览器半信半疑的脚本运行在沙箱时,它们应该只被允许访问来自同一站点的资源,而不是那些来自其它站点可能怀有恶意的资源。

      解决跨域的问题可以有两种方式,一种在前端采用JSONP实现,一种在后端服务器在响应头里面指定Access-Control-Allow-Origin。

    • JSONP---脚本标签自动请求--请求回来的内容执行个回调方法---解析数据
    • CORS 跨域资源共享,添加nuget包Microsoft.AspNet.WebApi.Cors,通过在配置中添加或者在Controller或Action上添加特性 EnableCors 来实现
    config.EnableCors(new EnableCorsAttribute("*", "*", "*"));//全部都允许
    • 自定义actionfilter--response增加头文件Access-Control-Allow-Origin 
  • 相关阅读:
    圣杯+双飞翼 自适应布局
    drupal8 用户指南
    运维笔记:zabbix的运用(1)安装过程
    Nginx的初识
    PHP 获取LDAP服务器Schema数据
    Nginx(alias 和 root的区别)
    vue开发--生成token并保存到本地存储中
    PHP程序员必须知道的两种日志
    MVC 应用程序级别捕捉异常
    消息队列MQ
  • 原文地址:https://www.cnblogs.com/jesen1315/p/12130979.html
Copyright © 2011-2022 走看看