使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【八】——Web Api的安全性

简介: 原文:使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【八】——Web Api的安全性系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 这一篇文章我们主要来探讨一下Web Api的安全性,到目前为止所有的请求都是走的Http协议(http://),因此客户端与服务器之间的通信是没有加密的。
原文: 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【八】——Web Api的安全性

系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html

前言

这一篇文章我们主要来探讨一下Web Api的安全性,到目前为止所有的请求都是走的Http协议(http://),因此客户端与服务器之间的通信是没有加密的。在本篇中,我们将在“StudentController”中添加身份验证功能——通过验证用户名与密码来判断是否是合法用户。众所周知,对于机密信息的传递,我们应该使用安全的Http协议(https://)来传输

在Web Api中强制使用Https

我们可以在IIS级别配置整个Web Api来强制使用Https,但是在某些情况下你可能只需要对某一个action强制使用Https,而其他的方法仍使用http。

为了实现这一点,我们将使用Web Api中的filters——filter(过滤器)的主要作用就是可以在我们执行方法之前执行一段代码。没接触过得可以通过下图简单理解下,大神跳过:

无标题

我们新创建的filter将用来检测是否是安全的,如果不是安全的,filter将终止请求并返回相应:请求必须是https。

具体做法:创建一个filter继承自AuthorizationFilterAttribute,重写OnAuthorization来实现我们的需求。

在网站根目录下创建“Filters”文件夹,新建一个类“ForceHttpsAttribute”继承自“System.Web.Http.Filters.AuthorizationFilterAttribute”,下面上代码:

public class ForceHttpsAttribute : AuthorizationFilterAttribute
    {
        public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
        {
            var request = actionContext.Request;
 
            if (request.RequestUri.Scheme != Uri.UriSchemeHttps)
            {
                var html = "<p>Https is required</p>";
 
                if (request.Method.Method == "GET")
                {
                    actionContext.Response = request.CreateResponse(HttpStatusCode.Found);
                    actionContext.Response.Content = new StringContent(html, Encoding.UTF8, "text/html");
 
                    UriBuilder httpsNewUri = new UriBuilder(request.RequestUri);
                    httpsNewUri.Scheme = Uri.UriSchemeHttps;
                    httpsNewUri.Port = 443;
 
                    actionContext.Response.Headers.Location = httpsNewUri.Uri;
                }
                else
                {
                    actionContext.Response = request.CreateResponse(HttpStatusCode.NotFound);
                    actionContext.Response.Content = new StringContent(html, Encoding.UTF8, "text/html");
                }
 
            }
        }
    }

在上面代码中,我们通过actionContext参数拿到request和response对象,我们判断客户端的请求:如果不是https,那么直接响应客户端应该使用https。

在这里,我们需要区分请求是Get还是其他(Post,Delete,Put),因为对于使用了Http的Get请求来访问资源,我们将使用https创建一个连接并添加在响应Header的Location中。这样做了之后客户端就会自动使用https来发送Get请求了。

对于非Get请求,直接返回404,并通知客户端必须使用https来请求

如果我们打算在整个项目中使用,那么在“WebAPIConfig”类中做如下设置:

public static void Register(HttpConfiguration config)
   {
       config.Filters.Add(new ForceHttpsAttribute());
   }

如果我们相对具体的Controller或Action设置时,可以做如下设置:

//对于整个Controller强制使用Https
[Learning.Web.Filters.ForceHttps()]
    public class CoursesController : BaseApiController
    {
    //仅对这个方法强制使用Https
        [Learning.Web.Filters.ForceHttps()]
            public HttpResponseMessage Post([FromBody] CourseModel courseModel)
            {
 
        }
}

使用Basic Authentication验证用户

到目前为止,我们提供的所有Api都是公开的,任何人都能访问。但在真是场景中却是不可取的,对于某些数据,只有通过认证的用户才能访问,我们这里有两个地方恰好说明这一点:

1.当客户端发送Get请求道“http://{your_port}/api/students/{userName}“的时候.例如:通过上述URI访问userNme为“TaiseerJoudeh”的信息时,我们必须让客户端提供TaiseerJoudeh相应的用户名和密码,对于没有提供验证信息的用户我们就不让访问,因为学生信息包含一些重要的私人信息(email,birthday等)。

2.当客户端发送Post请求到“http://{your_port}/api/courses/2/students/{userName}“的时候,这意味着给学生选课,我们可以想一下,这里如果不做验证,那么所有人都能随便给某个学生选课,那么不就乱了么。

对于上面的场景,我们使用Basic Authentication来进行身份验证,主要思路是使用filter从请求header部分获取身份信息,校验验证类型是否为“basic”,然后校验内容,正确就放行,否则返回401 (Unauthorized)状态码。

在上代码前,解释一下下basic authentication:

什么是basic authentication?

它意味着在正式处理Http请求之前对请求者身份的校验,这可以防止服务器受到DoS攻击(Denial of service attacks)。原理是:客户端在发送Http请求的时候在Header部分提供一个基于Base64编码的用户名和密码,形式为“username:password”,消息接收者(服务器)进行验证,通过后继续处理请求。

由于用户名和密码仅适用base64编码,因此为了保证安全性,basic authentication通常是基于SSL连接(https)

为了在我们的api中使用,创建一个类“LearningAuthorizeAttribute”继承自System.Web.Http.Filters.AuthorizationFilterAttribute

public class LearningAuthorizeAttribute : AuthorizationFilterAttribute
    {
 
        [Inject]
        public LearningRepository TheRepository { get; set; }
 
        public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
        {
            //forms authentication Case that user is authenticated using forms authentication
            //so no need to check header for basic authentication.
            if (Thread.CurrentPrincipal.Identity.IsAuthenticated)
            {
                return;
            }
 
            var authHeader = actionContext.Request.Headers.Authorization;
 
            if (authHeader != null)
            {
                if (authHeader.Scheme.Equals("basic", StringComparison.OrdinalIgnoreCase) &&
                    !String.IsNullOrWhiteSpace(authHeader.Parameter))
                {
                    var credArray = GetCredentials(authHeader);
                    var userName = credArray[0];
                    var password = credArray[1];
 
                    if (IsResourceOwner(userName, actionContext))
                    {
                        //You can use Websecurity or asp.net memebrship provider to login, for
                        //for he sake of keeping example simple, we used out own login functionality
                        if (TheRepository.LoginStudent(userName, password))
                        {
                            var currentPrincipal = new GenericPrincipal(new GenericIdentity(userName), null);
                            Thread.CurrentPrincipal = currentPrincipal;
                            return;
                        }
                    }
                }
            }
 
            HandleUnauthorizedRequest(actionContext);
        }
 
        private string[] GetCredentials(System.Net.Http.Headers.AuthenticationHeaderValue authHeader)
        {
 
            //Base 64 encoded string
            var rawCred = authHeader.Parameter;
            var encoding = Encoding.GetEncoding("iso-8859-1");
            var cred = encoding.GetString(Convert.FromBase64String(rawCred));
 
            var credArray = cred.Split(':');
 
            return credArray;
        }
 
        private bool IsResourceOwner(string userName, System.Web.Http.Controllers.HttpActionContext actionContext)
        {
            var routeData = actionContext.Request.GetRouteData();
            var resourceUserName = routeData.Values["userName"] as string;
 
            if (resourceUserName == userName)
            {
                return true;
            }
            return false;
        }
 
        private void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
        {
            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
 
            actionContext.Response.Headers.Add("WWW-Authenticate",
                                               "Basic Scheme='eLearning' location='http://localhost:8323/account/login'");
 
        }
    }

我们重写了“OnAuthorization”,实现如下功能:

1.从请求Header中获取校验数据

2.判断验证信息类型为“basic”并包含base64编码

3.将base64编码转化为string,并提取用户名和密码

4.校验提供的验证信息是否与访问的资源信息相同(学生的详细信息只能由他自己访问)

5.去数据库校验用户名及密码

6.如果校验通过,则设置Thread的CurrentPrincipal,使本次接下来的请求都是通过校验的。

7.校验没通过,返回401(Unauthorized)并添加一个WWW-Authenticate响应头,根据这个请求,客户端可以添加相应的验证信息

在代码中实现起来就很简单了,上两个Attribute就完了:

public class StudentsController : BaseApiController
    {
        [LearningAuthorizeAttribute]
        public HttpResponseMessage Get(string userName)
            {
 
            }
    }
public class EnrollmentsController : BaseApiController
    {
        [LearningAuthorizeAttribute]
        public HttpResponseMessage Post(int courseId, [FromUri]string userName, [FromBody]Enrollment enrollment)
            {
 
            }
    }

测试成果

使用测试工具发送如下请求:

image

由于没有提供身份验证,于是得到如下响应:

image

取消:

image

去数据库找到对应的用户名和密码输入,得到如下结果:

image

总结

因为 Base Authentication 的安全性较差,但对于无 Cookie 的 Web Api 来说,应用上非常的简单和方便。

Base Authentication 最大的缺点是凭据会被浏览器缓存——直到你关闭浏览器为止。如果你已经对某个URI获得了授权,浏览器就会在授权头发送相应的凭据,这使其更容易受到跨站点请求伪造(CSRF)攻击

Base Authentication 通常需要使用HTTPS方式进行加密处理。

源码地址:https://github.com/fzrain/WebApi.eLearning

目录
相关文章
|
10天前
|
安全 数据挖掘 API
车辆车型大全 API 实战指南:推动交通行业智能化
车辆车型大全API由探数平台提供,旨在解决企业班车、物流运输及汽车销售等行业对标准化车型数据的需求。传统人工维护车型库效率低且易出错,而该API覆盖主流品牌与车系,包含品牌、车系、销售车型及配置参数等详细信息,适用于车队管理、电商平台及汽车资讯平台。API提供四个子接口:获取品牌、车系、销售车型与配置详情信息,支持高效查询。通过HTTP POST请求即可调用,返回结构化数据,助力企业实现智能化运营与科学决策,在绿色智能交通时代发挥重要作用。
62 4
|
24天前
|
监控 供应链 数据挖掘
淘宝商品详情API接口解析与 Python 实战指南
淘宝商品详情API接口是淘宝开放平台提供的编程工具,支持开发者获取商品详细信息,包括基础属性、价格、库存、销售策略及卖家信息等。适用于电商数据分析、竞品分析与价格策略优化等场景。接口功能涵盖商品基础信息、详情描述、图片视频资源、SKU属性及评价统计的查询。通过构造请求URL和签名,可便捷调用数据。典型应用场景包括电商比价工具、商品数据分析平台、供应链管理及营销活动监控等,助力高效运营与决策。
146 26
|
5天前
|
新能源 API 开发者
车辆限行查询API的实战指南:让限行管理从此 “有码可循”
随着全国机动车保有量突破4.53亿辆,交通拥堵与污染问题日益严峻,各城市陆续实施限行政策。探数API推出的车辆限行查询服务覆盖200+城市,提供实时限行数据,包括本地/外地燃油车及新能源车的限行规则、区域和时间等信息。其功能涵盖单个城市限行政策查询与支持城市的全面列表,助力用户精准规划出行。通过HTTP POST请求即可轻松接入,适用于导航平台和个人开发者。在“双碳”目标下,该API推动绿色出行与智能交通发展,为个人、企业和城市治理提供高效解决方案。
46 2
|
5天前
|
传感器 人工智能 安全
运营商三要素API的实战指南:实现 “人 - 证 - 号” 三位一体核验
在数字身份欺诈频发的背景下,传统单点验证已无法满足高安全需求。探数API推出的“运营商三要素核验API”,通过姓名、身份证号、手机号的三重交叉验证,构建起“铁三角”防线,广泛适用于金融、政务、电商等领域。该API支持一致性验证及基础信息返回(可选),具备高准确性与防伪性,远超单一或双因素验证方式。其调用流程简单,提供Python示例代码及异常处理建议,助力打造更安全的数字身份体系,成为连接多领域的关键桥梁。未来,多因子融合的身份认证将成为趋势,而三要素核验API正是当前可信数字身份的重要基石。
49 2
|
6天前
|
安全 物联网 API
核验身份证的一致性API的实战指南
随着网络空间安全问题日益突出,实名制成为保障安全与秩序的重要手段。探数API的身份证实名认证工具通过姓名和身份证号核验用户身份真实性,并返回扩展信息,广泛应用于各行业。本文介绍了其实现功能、调用流程及代码示例,同时解答了关于个人信息安全等常见疑问。接入该API不仅满足合规要求,更能提升用户信任,降低运营风险,共同构建安全高效的数字未来。
46 1
|
12天前
|
人工智能 JSON 安全
VIN码查询_标准版API:帮助解锁车辆的“身份证”详细信息的实战指南
VIN码(车辆识别号码)是由17位字母和数字组成的全球唯一编码,相当于汽车的“身份证”。通过解析VIN码,可获取品牌、车系、生产年份等关键信息。探数API平台的VIN码查询API(标准版),只需输入VIN码即可返回完整车辆配置信息。 该API适用于多种场景:电商平台可自动填充商品详情,提升准确性;维修行业能精准匹配零件与诊断需求;二手车市场则增强交易透明度与安全性。其调用流程简单,包括准备VIN码、构造请求、处理响应及异常处理。 VIN码不仅是查询工具,更是连接制造、销售、维修、保险等环节的纽带。
62 6
|
10天前
|
JSON 供应链 API
商品条码查询 API 实战指南:掌握商品“唯一身份标识”
商品条码查询API简介:基于1974年诞生的条码技术,该API通过输入13/14位条码,快速获取商品基本信息(名称、品牌、规格等)和成分信息(营养成分、配料表等)。其核心功能包括商品条码查询接口与成分查询接口,广泛应用于零售、电商、物流及健康饮食等领域。支持HTTP POST请求,提供便捷的代码调用示例。作为数字化转型的重要工具,它不仅方便消费者查询商品详情,还助力商家优化库存管理与销售流程,提升运营效率。
122 3
|
6天前
|
边缘计算 API 决策智能
淘宝/天猫商品详情API返回值深度解析:应用价值与实战策略
本文深入解析淘宝/天猫商品详情API返回值的应用价值,涵盖核心字段、技术架构、应用场景与合规要求四大维度。从num_iid到skus,详解数据结构;通过分布式架构与边缘计算优化性能;探讨自动化调价、精准推荐等商业场景;并强调合规调用与开发者工具支持。助力企业提升运营效率与用户体验,在电商竞争中抢占先机。
|
6天前
|
搜索推荐 API 数据安全/隐私保护
淘宝电商API应用实战指南,手把手教你玩转电商!
本文详细解析了淘宝电商API的应用方法,涵盖商品详情、订单处理、用户分析及营销推广等核心功能。通过自动化管理和数据驱动决策,商家可提升运营效率与用户体验。文章还提供了Python实战代码示例,帮助开发者快速接入与调用API。遵守安全规范并优化策略,将助力商家在竞争中脱颖而出,实现电商智能化升级。
|
24天前
|
人工智能 缓存 搜索推荐
1688图片搜索API接口解析与 Python实战指南
1688图片搜索API接口支持通过上传图片搜索相似商品,适用于电商及商品推荐场景。用户上传图片后,经图像识别提取特征并生成关键词,调用接口返回包含商品ID、标题和价格的相似商品列表。该接口需提供图片URL或Base64编码数据,还可附加分页与筛选参数。示例代码展示Python调用方法,调试时建议使用沙箱环境测试稳定性,并优化性能与错误处理逻辑。

热门文章

最新文章