当前位置:网站首页>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
边栏推荐
- 低代码工具有哪些特色?明眼人都能看出来的低代码两大发展轨迹!
- DOM case: 10 second countdown - write jump page related knowledge
- ShardingSphere-JDBC 关键字问题
- Linux 定时备份数据库并删除 N 天以前的数据
- Leetcode daily practice - 189. Rotation array
- 【Pytorch基础】torch.stack()函数解析
- 福建争抢VC/PE
- Kingbases SQL language reference manual of Jincang database (15. SQL statement: create materialized view to create schema)
- [internship experience] date verification
- 银行业务分类
猜你喜欢
![[PHP] save session data to redis](/img/29/70a9f330b9f912ccbd57e865372439.png)
[PHP] save session data to redis

IM即时通讯开发如何压缩移动网络下APP的流量消耗

Use of load balancing

What should we do about the fragmentation of internal information? Try this

Household deposits increased by 10.33 trillion yuan in the first half of the year, with an average of 57.1 billion deposits pouring into banks every day

2022年下半年(软考高级)信息系统项目管理师报名条件

Analysis of interface testing

How to uninstall win11 edge? The method tutorial of completely uninstalling win11 edge browser

【JVM 系列】JVM 调优

3万脱发人,撑起一个IPO
随机推荐
银行业务分类
答应我,看完别再写狗屎代码了。。
开源 | AREX-携程无代码侵入的流量回放实践
网红辣条抓不住年轻人
金融机构导图
ipad下载的文件在哪里可以找到
计算机专业面试题目总结,总导航
numpy.zeros_like
LeetCode_回溯_中等_216.组合总和 III
Detailed explanation of Yolo v1
JWT 实现登录认证 + Token 自动续期方案,这才是正确的使用姿势!
金仓数据库 KingbaseES SQL 语言参考手册 (19. SQL语句: DROP TABLE 到 LOAD)
Canvas graphics
【OBS】Dropped Frames And General Connection Issues
Leetcode daily practice - 27. Remove elements
Analysis of interface testing
计算机组成原理常见面试题目总结,含答案
Where can I find the files downloaded from iPad
Leetcode daily practice - 26. Delete duplicates in an ordered array
2022 极术通讯-安谋科技开启商业化新篇章