在 Azure 门户>应用程序注册中注册应用程序后,从 UI 生成的 .net core 3.1 API 项目中的令牌验证失败

Posted

技术标签:

【中文标题】在 Azure 门户>应用程序注册中注册应用程序后,从 UI 生成的 .net core 3.1 API 项目中的令牌验证失败【英文标题】:Token validation fails in .net core 3.1 API project which is generated from the UI,after registrating the application in Azure Portal>App registration 【发布时间】:2021-12-06 02:34:24 【问题描述】:

我添加了一个中间件来处理后端 .NET core 3.1 项目中的令牌验证。

Startup.cs 更改

app.UseRouting();
app.UserAuthorization();
app.UserMiddleware<JWTMiddleware>();

JWTMiddleware.cs

    using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WebAPI

    public class JwtMiddleware
    
        private readonly RequestDelegate _next;
        //private readonly AppSettings _appSettings;

        //public JwtMiddleware(RequestDelegate next, IOptions<AppSettings> appSettings)
        public JwtMiddleware(RequestDelegate next)
        
            _next = next;
            //_appSettings = appSettings.Value;
        

        public async Task Invoke(HttpContext context)
        
            var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();

            if (token != null)
                await attachAccountToContext(context, token);

            await _next(context);
        

        private async Task attachAccountToContext(HttpContext context, string token)
        
            try
            
                var tokenHandler = new JwtSecurityTokenHandler();
                var secretkey="";
                var key = Encoding.ASCII.GetBytes(secretKey);
                var clientID = "MYCLIENTID";
                tokenHandler.ValidateToken(token, new TokenValidationParameters
                
                    ValidIssuer= "https://login.microsoftonline.com/MYTENNANTID/v2.0",
                    ValidAudience=clientID,
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = false,
                    ValidateAudience = false,
                    
                    ClockSkew = TimeSpan.Zero,
                    
                , out SecurityToken validatedToken);

                var jwtToken = (JwtSecurityToken)validatedToken;
                var accountId = int.Parse(jwtToken.Claims.First(x => x.Type == "upn").Value);

                // attach account to context on successful jwt validation
                context.Items["Account"] = accountId;
            
            catch(Exception ex)
            

                // do nothing if jwt validation fails
                // account is not attached to context so request won't have access to secure routes
            
        
    
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class AuthorizeAttribute : Attribute, IAuthorizationFilter
    
        public void OnAuthorization(AuthorizationFilterContext context)
        
            var UserId = context.HttpContext.Items["Account"];
            if (UserId == null)
            
                // not logged in
                context.Result = new JsonResult(new  message = "Unauthorized" )  StatusCode = StatusCodes.Status401Unauthorized ;
            
        
    

问题是,验证总是失败。它给出了一个例外。

我在哪里可以找到钥匙。 我已经在 Azure 门户中添加了应用程序,并获得了一个 clientID 并创建了一个秘密。 之后,我使用这些详细信息在 UI 上生成一个令牌,并将其添加到 Authorization 标头中,并将其传递给应该对其进行验证的 API 项目。 我知道 IssuerSigningKey 的创建方式有问题,但无法弄清楚它是什么。我曾尝试将密钥作为密钥传递,但效果不佳。

【问题讨论】:

为什么不使用内置的JWT认证呢?您为它定义权限和受众,它会为您处理很多事情。 你能帮我一些链接吗,我是 .net 核心的新手,我得到的任何地方都在使用自定义中间件进行身份验证。 这个样本至少是好的:github.com/Azure-Samples/…。它使用更高级别的 Microsoft.Identity.Web 库进行身份验证。您可以在这里找到更多示例:docs.microsoft.com/en-us/azure/active-directory/develop/… 【参考方案1】:

这是我尝试过的,对我有帮助

var tokenHandler = new JwtSecurityTokenHandler();
            string secretKey = _configuration.GetValue<string>("AzureSSO:Secret");
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            rsa.ImportParameters(
              new RSAParameters()
              
                  Modulus = FromBase64Url(_configuration.GetValue<string>("AzureSSO:Modulus")),
                  Exponent = FromBase64Url(_configuration.GetValue<string>("AzureSSO:Exponent"))
              );
            var clientID = _configuration.GetValue<string>("AzureSSO:ClientID");
            tokenHandler.ValidateToken(token, new TokenValidationParameters
            
                ValidIssuer= _configuration.GetValue<string>("AzureSSO:Issuer"),
                ValidAudience=clientID,
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new RsaSecurityKey(rsa),
                ValidateIssuer = false,
                ValidateAudience = false,
                ClockSkew = TimeSpan.Zero,
                
            , out SecurityToken validatedToken);

我从发现文档端点找到了模数和指数,并使用它们来创建密钥。

【讨论】:

【参考方案2】:

谢谢CB_Ron 和juunas。发布您的建议作为帮助其他社区成员的答案。

RsaSha256/RSA256 不是受支持的对称算法。你需要尝试对称算法,比如SecurityAlgorithms.HmacSha256

您可以参考Code Samples for Microsoft Identity Platform、IDX10634: Unable to create the SignatureProvider、JWT error IDX10634: Unable to create the SignatureProvider C#和implement RSA in .NET core

【讨论】:

以上是关于在 Azure 门户>应用程序注册中注册应用程序后,从 UI 生成的 .net core 3.1 API 项目中的令牌验证失败的主要内容,如果未能解决你的问题,请参考以下文章

在多租户应用程序中如何检查应用程序在 Azure 门户中注册的租户数据?

以编程方式注册 Azure 应用程序(图形 API)

旧版Azure AD应用程序注册中的“授予权限”按钮与新体验中的“授予管理员同意”有何不同?

[在Azure目录中注册应用程序时谁获得许可?

Azure 通知中心和 Apple APNS 推送通知取消注册设备

使用 Azure 中的集线器注册推送通知时,Xamarin.iOS 本机崩溃错误 SIGSEGV