ASP.NET Core 6基本身份验证问题与Postman Post方法

pu3pd22g  于 2022-11-07  发布在  Postman
关注(0)|答案(1)|浏览(273)

我在Postman中调用post方法时遇到了这个返回错误,但Project可以为get方法工作。Project是一个简单的Web API,带有X-UserID的自定义基本身份验证和hmac哈希的请求主体检查:

{
        "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
        "title": "One or more validation errors occurred.",
        "status": 400,
        "traceId": "00-e3ed0f946eea3d3837b9fb1ab1a90264-c22b6030e59a8653-00",
        "errors": {
            "$": [
                "The input does not contain any JSON tokens. Expected the input to start with a valid JSON token, when isFinalBlock is true. Path: $ | LineNumber: 0 | BytePositionInLine: 0."
            ],
            "user": [
                "The user field is required."
            ]
        }
    }

下面是处理程序的代码:

using System.Net.Http.Headers;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Options;

namespace test25_08.Authentication;

public class BasicAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
    private readonly ApplicationDbContext _context;

    public BasicAuthHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger,
        UrlEncoder encoder, ISystemClock clock, ApplicationDbContext context) : base(options, logger, encoder, clock)
    {
        _context = context;
    }

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        string method = Request.Method;

        if (!Request.Headers.ContainsKey("X-UserId"))
        {
            return AuthenticateResult.Fail("No header found");
        }

        var headerValue = AuthenticationHeaderValue.Parse(Request.Headers["X-UserId"]);

        var bytes = Convert.FromBase64String(headerValue.Parameter);

        var credentials = Encoding.UTF8.GetString(bytes);

        if (!string.IsNullOrEmpty(credentials))
        {
            var strings = credentials.Split(":");

            var userId = strings[0];
            var password = strings[1];

            var user = _context.Users
                .FirstOrDefault(item =>
                    item.Id == Convert.ToInt32(userId) && item.Password == password
                );

            if (user == null)
            {
                return AuthenticateResult.Fail("No user found");
            }

            if (method.Equals("POST"))
            {
                string secret = "secret";
                var headerValue2 = AuthenticationHeaderValue.Parse(Request.Headers["X-Digest"]);

                if (!Request.Headers.ContainsKey("X-Digest"))
                {
                    return AuthenticateResult.Fail("No header found");
                }

                Request.EnableBuffering();

                Request.Body.Position = 0;

                string requestBody = await new StreamReader(Request.Body).ReadToEndAsync();
                string replace = Regex.Replace(requestBody, @"\s+", "");

                if (!headerValue2.Parameter!.Equals(HashString(replace, secret)))
                {
                    return AuthenticateResult.Fail("Request body doesn't match");
                }
            }

            var claim = new[] { new Claim(ClaimTypes.Name, userId) };
            var identity = new ClaimsIdentity(claim, Scheme.Name);
            var principal = new ClaimsPrincipal(identity);
            var ticket = new AuthenticationTicket(principal, Scheme.Name);

            return AuthenticateResult.Success(ticket);
        }

        return AuthenticateResult.Fail("UnAuthorized");
    }

    static string HashString(string stringToHash, string hachKey)
    {
        UTF8Encoding myEncoder = new UTF8Encoding();
        byte[] key = myEncoder.GetBytes(hachKey);
        byte[] text = myEncoder.GetBytes(stringToHash);
        HMACSHA1 myHmacsha1 = new HMACSHA1(key);
        byte[] hashCode = myHmacsha1.ComputeHash(text);
        string hash = BitConverter.ToString(hashCode).Replace("-", "");
        return hash.ToLower();
    }
}

这是Program.cs中的配置:

using Microsoft.AspNetCore.Authentication;
using Microsoft.EntityFrameworkCore;
using test25_08;
using test25_08.Authentication;
using test25_08.Service;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));

// builder.Services.AddIdentity<User, IdentityRole>()
//     .AddEntityFrameworkStores<ApplicationDbContext>()
//     .AddDefaultTokenProviders();

builder.Services.AddScoped<IWalletService, WalletService>();

builder.Services
    .AddAuthentication("BasicAuthHandler").AddScheme<AuthenticationSchemeOptions,BasicAuthHandler>("BasicAuthHandler", null);

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
app.UseHttpsRedirection();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();

有人能找到为什么这个问题在 Postman ?
已更新
如果取消选中来自Postman的X-Digest,并在处理程序中使用if (method.Equals("POST")){...},则一切正常。

curl --location --request POST 'https://localhost:44358/api/v1/Users' \
--header 'X-UserId: basic MTphYWE=' \
--header 'X-Digest: basic 707cc304a905d573cd196e2ace1eb565e3c04a82' \
--header 'Content-Type: application/json' \
--data-raw '{
  "id": 0,
  "userName": "string",
  "password": "string",
  "fullName": "string",
  "passportNumber": "string",
  "borNDate": "2022-09-07T03:14:00.985Z",
  "isAuthenticated": true
}'
brccelvz

brccelvz1#

Alhamdullah,我找到了解决方案问题是在阅读请求主体后,我们丢失了请求主体中数据我找到了带有Request.PeekBody()Request.PeekBodyAsync() Request.Body.Peeker Nuget包,您可以将主体作为字符串读取,而不会丢失数据Link to source

相关问题