当前位置:网站首页>Use request header authentication to test API interfaces that need authorization
Use request header authentication to test API interfaces that need authorization
2022-07-26 20:07:00 【biyusr】
Use request header authentication to test what needs authorization API Interface
Intro
There are some interfaces that need authentication and authorization. When writing test cases, they usually obtain one first token, Then call the interface , In fact, doing so is very inflexible , On the one hand, there are certain security problems , obtain token There may be some test data such as user name and password , There is also access to token If the global use the same token Will be very inflexible , If I want to test without user information, it's relatively simple , I can not pass token, If token There are two roles in , When I want to test another character , You can only add a role to this test user and then get token, This is very inflexible , So I try to put the code of custom request header authentication written before , Sort it out , Integrated into one nuget In the bag for the convenience of other projects ,nuget Bag is WeihanLi.Web.Extensions, The source code is here https://github.com/WeihanLi/WeihanLi.Web.Extensions If you want to change it yourself, you can use it directly , At present, authentication based on request header and authentication based on QueryString There are two authentication methods .
Realization effect
Dynamically configure user information based on the request header , Add whatever information you need in the request header , Examples are as follows :


Let's take another example of unit testing :
]public async Task MakeReservationWithUserInfo(){using var request = new HttpRequestMessage(HttpMethod.Post, "/api/reservations");request.Headers.TryAddWithoutValidation("UserId", GuidIdGenerator.Instance.NewId()); // user Idrequest.Headers.TryAddWithoutValidation("UserName", Environment.UserName); // user namerequest.Headers.TryAddWithoutValidation("UserRoles", "User,ReservationManager"); // User rolesrequest.Content = new StringContent([email protected]"{ {""reservationUnit"":""nnnnn"",""reservationActivityContent"":""13211112222"",""reservationPersonName"":"" Thank you thank you "",""reservationPersonPhone"":""13211112222"",""reservationPlaceId"":""f9833d13-a57f-4bc0-9197-232113667ece"",""reservationPlaceName"":"" The first multifunctional hall "",""reservationForDate"":""2020-06-13"",""reservationForTime"":""10:00~12:00"",""reservationForTimeIds"":""1""}}", Encoding.UTF8, "application/json");using var response = await Client.SendAsync(request);Assert.Equal(HttpStatusCode.OK, response.StatusCode);}
Implementation principle analysis
The implementation principle is actually quite simple , Is to achieve a kind of based on header Custom authentication mode , from header Get user information and authenticate , The core code is as follows :
protected override async Task<AuthenticateResult> HandleAuthenticateAsync(){if (await Options.AuthenticationValidator(Context)){var claims = new List<Claim>();if (Request.Headers.TryGetValue(Options.UserIdHeaderName, out var userIdValues)){claims.Add(new Claim(ClaimTypes.NameIdentifier, userIdValues.ToString()));}if (Request.Headers.TryGetValue(Options.UserNameHeaderName, out var userNameValues)){claims.Add(new Claim(ClaimTypes.Name, userNameValues.ToString()));}if (Request.Headers.TryGetValue(Options.UserRolesHeaderName, out var userRolesValues)){var userRoles = userRolesValues.ToString().Split(new[] { Options.Delimiter }, StringSplitOptions.RemoveEmptyEntries);claims.AddRange(userRoles.Select(r => new Claim(ClaimTypes.Role, r)));}if (Options.AdditionalHeaderToClaims.Count > 0){foreach (var headerToClaim in Options.AdditionalHeaderToClaims){if (Request.Headers.TryGetValue(headerToClaim.Key, out var headerValues)){foreach (var val in headerValues.ToString().Split(new[] { Options.Delimiter }, StringSplitOptions.RemoveEmptyEntries)){claims.Add(new Claim(headerToClaim.Value, val));}}}}// claims identity 's authentication type can not be null https://stackoverflow.com/questions/45261732/user-identity-isauthenticated-always-false-in-net-core-custom-authenticationvar principal = new ClaimsPrincipal(new ClaimsIdentity(claims, Scheme.Name));var ticket = new AuthenticationTicket(principal,Scheme.Name);return AuthenticateResult.Success(ticket);}return AuthenticateResult.NoResult();}
In fact, it is to read the information of the request header to Claims, And then return a ClaimsPrincipal and AuthenticationTicket, In the reading header There was one before AuthenticationValidator It is used to verify whether the request meets the use Header authentication , It's based on HttpContext Assertion delegate for (Func<HttpContext, Task<bool>>), The default implementation is to verify whether there is UserId Corresponding Header, If you want to modify it, you can use Startup To configure the
Examples of use
Startup To configure , Like other authentication methods ,Header Certification and Query Certification also provides a AuthenticationBuilder An extension of , Only need services.AddAuthentication() Add... After Header The authentication mode is ok , Examples are as follows :
services.AddAuthentication(HeaderAuthenticationDefaults.AuthenticationSchema).AddQuery(options =>{options.UserIdQueryKey = "uid";}).AddHeader(options =>{options.UserIdHeaderName = "X-UserId";options.UserNameHeaderName = "X-UserName";options.UserRolesHeaderName = "X-UserRoles";});
default Header yes UserId/UserName/UserRoles, You can also customize the configuration to meet your needs , If you just want to add a transformation, you can configure AdditionalHeaderToClaims Increase the request header you need => Claims transformation ,AuthenticationValidator You can also customize it , As mentioned above, we will first verify whether it is necessary to read Header, It will not be read until the verification passes Header Information and certification
Test examples
There is an interface that I need to login to access , Need user information , Similar to the following
[HttpPost][Authorize]public async Task<IActionResult> MakeReservation([FromBody] ReservationViewModel model){// ...}
In the test code, I configured Header authentication , Directly pass the request Header To control user information
Startup To configure :
services.AddAuthentication(HeaderAuthenticationDefaults.AuthenticationSchema).AddHeader()// Use Query authentication//.AddAuthentication(QueryAuthenticationDefaults.AuthenticationSchema)//.AddQuery();
Test code :
[Fact]public async Task MakeReservationWithUserInfo(){using var request = new HttpRequestMessage(HttpMethod.Post, "/api/reservations");request.Headers.TryAddWithoutValidation("UserId", GuidIdGenerator.Instance.NewId());request.Headers.TryAddWithoutValidation("UserName", Environment.UserName);request.Headers.TryAddWithoutValidation("UserRoles", "User,ReservationManager");request.Content = new StringContent([email protected]"{ {""reservationUnit"":""nnnnn"",""reservationActivityContent"":""13211112222"",""reservationPersonName"":"" Thank you thank you "",""reservationPersonPhone"":""13211112222"",""reservationPlaceId"":""f9833d13-a57f-4bc0-9197-232113667ece"",""reservationPlaceName"":"" The first multifunctional hall "",""reservationForDate"":""2020-06-13"",""reservationForTime"":""10:00~12:00"",""reservationForTimeIds"":""1""}}", Encoding.UTF8, "application/json");using var response = await Client.SendAsync(request);Assert.Equal(HttpStatusCode.OK, response.StatusCode);}[Fact]public async Task MakeReservationWithInvalidUserInfo(){using var request = new HttpRequestMessage(HttpMethod.Post, "/api/reservations");request.Headers.TryAddWithoutValidation("UserName", Environment.UserName);request.Content = new StringContent([email protected]"{ {""reservationUnit"":""nnnnn"",""reservationActivityContent"":""13211112222"",""reservationPersonName"":"" Thank you thank you "",""reservationPersonPhone"":""13211112222"",""reservationPlaceId"":""f9833d13-a57f-4bc0-9197-232113667ece"",""reservationPlaceName"":"" The first multifunctional hall "",""reservationForDate"":""2020-06-13"",""reservationForTime"":""10:00~12:00"",""reservationForTimeIds"":""1""}}", Encoding.UTF8, "application/json");using var response = await Client.SendAsync(request);Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);}[Fact]public async Task MakeReservationWithoutUserInfo(){using var request = new HttpRequestMessage(HttpMethod.Post, "/api/reservations"){Content = new StringContent(@"{""reservationUnit"":""nnnnn"",""reservationActivityContent"":""13211112222"",""reservationPersonName"":"" Thank you thank you "",""reservationPersonPhone"":""13211112222"",""reservationPlaceId"":""f9833d13-a57f-4bc0-9197-232113667ece"",""reservationPlaceName"":"" The first multifunctional hall "",""reservationForDate"":""2020-06-13"",""reservationForTime"":""10:00~12:00"",""reservationForTimeIds"":""1""}",Encoding.UTF8, "application/json")};using var response = await Client.SendAsync(request);Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);}
More
QueryString Authentication and request header authentication are similar , No more details here , Just transfer the parameters on the request header to QueryString Yes , If you think it's not easy to use, you can directly Github Find the source code modification , Welcome, too PR, Source code address :https://github.com/WeihanLi/WeihanLi.Web.Extensions
Reference
https://github.com/WeihanLi/WeihanLi.Web.Extensions
https://www.nuget.org/packages/WeihanLi.Web.Extensions
https://github.com/OpenReservation/ReservationServer/blob/dev/ActivityReservation.API.Test/TestStartup.cs
https://github.com/OpenReservation/ReservationServer/blob/dev/ActivityReservation.API.Test/Controllers/ReservationControllerTest.cs
https://www.cnblogs.com/weihanli/p/cutom-authentication-in-aspnetcore.html
边栏推荐
- 高瓴加入的PRI,君联、华控、盛世、绿动等百家机构都杀进去了
- 企业数字化转型成大趋势,选对在线协作工具很重要
- 使用三重损失和孪生神经网络训练大型类目的嵌入表示
- numpy.zeros_like
- tf.GraphKeys
- BluePrism流程业务对象的组件功能介绍-RPA第三章
- EFCore Migrations的深入研究
- Leetcode daily practice - 26. Delete duplicates in an ordered array
- 并行执行(二)、multiprocessing
- What is a knowledge management system? You need to know this
猜你喜欢

ShardingSphere-JDBC 关键字问题

【实习经验】异常处理与访问url结果响应数据处理

千亿酸奶赛道,乳企巨头和新品牌打响拉锯战

网红辣条抓不住年轻人

Intensive reading of the paper: yolov2 - yolo9000: better, faster, stronger

企业内部信息碎片化该怎么办?不妨试试这样做

【MySQL】 - 索引原理与使用

Canvas graphics

DOM case: 10 second countdown - write jump page related knowledge

What should we do about the fragmentation of internal information? Try this
随机推荐
十大排序详解
金仓数据库 KingbaseES SQL 语言参考手册 (12. SQL语句:ALTER LANGUAGE 到 ALTER SUBSCRIPTION)
Jincang database kingbasees SQL language reference manual (18. SQL statement: drop materialized view to drop synonym)
几张图帮你捋清“中国金融机构体系”
计算机网络常见面试题目总结,含答案
【OBS】解决OBS推两个rtmp流 + 带时间戳问题
记一次 .NET 某物管后台服务 卡死分析
svn使用碎碎念
使用ECS和OSS搭建个人网盘
企业内部信息碎片化该怎么办?不妨试试这样做
移动端video兼容你需要知道的几点
【JVM 系列】JVM 调优
【实习经验】异常处理与访问url结果响应数据处理
【机器学习】变量间的相关性分析
福建争抢VC/PE
Excel-VBA 快速上手(十二、Like 比较的常见用法)
plsql包
[internship experience] exception handling and URL result response data processing
How to uninstall win11 edge? The method tutorial of completely uninstalling win11 edge browser
cv2.resize()