using Bestrane.OPS.Core;
using IdentityModel;
using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
namespace Bestrane.OPS.API.Attributes
{
public class JwtAuthenticationAttribute : AuthorizationFilterAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
if (!IsAuthorized(actionContext))
{
HandleUnauthorizedRequest(actionContext);
}
}
private bool IsAuthorized(HttpActionContext actionContext)
{
// Get the Authorization header from the request
var authHeader = actionContext.Request.Headers.Authorization;
if (authHeader != null && authHeader.Scheme.Equals("Bearer", StringComparison.OrdinalIgnoreCase))
{
try
{
var policyNames = new List<string> { "eta", "pod", "routeplanner" };
var accessToken = authHeader.Parameter;
string rootDirectory = AppContext.BaseDirectory;
var configReader = new JsonConfigReader($"{rootDirectory}/AzureConfig.json");
var clientId = configReader.GetValueByNodePath<string>("AzureAd/ClientId");
var tenantId = configReader.GetValueByNodePath<string>("AzureAd/TenantId");
var openIdConfigurationEndpoint = $"https://login.microsoftonline.com/{tenantId}/v2.0/.well-known/openid-configuration";
IConfigurationManager<OpenIdConnectConfiguration> configurationManager =
new ConfigurationManager<OpenIdConnectConfiguration>(openIdConfigurationEndpoint,
new OpenIdConnectConfigurationRetriever(),
new HttpDocumentRetriever());
OpenIdConnectConfiguration openIdConfig = configurationManager.GetConfigurationAsync(CancellationToken.None).Result;
var keys = openIdConfig.SigningKeys.Where(x => x.GetType() == typeof(Microsoft.IdentityModel.Tokens.X509SecurityKey)).ToList();
TokenValidationParameters validationParameters = new TokenValidationParameters
{
ValidateAudience = false,
ValidateIssuer = false,
IssuerSigningKeys = keys,
ValidateLifetime = false,
ValidateIssuerSigningKey = false,
TokenReader = (string token1, TokenValidationParameters parameters) =>
{
string[] parts = token1.Split('.');
string header = parts[0];
string payload = parts[1];
string signature = parts[2];
var tokenHandler = new JwtSecurityTokenHandler();
var jsonToken = tokenHandler.ReadJwtToken(token1);
if (jsonToken.Header.TryGetValue("nonce", out object nonceAsObject))
{
string plainNonce = nonceAsObject.ToString();
using (SHA256 sha256 = SHA256.Create())
{
byte[] hashedNonceAsBytes = sha256.ComputeHash(
System.Text.Encoding.UTF8.GetBytes(plainNonce));
string hashedNonce = Base64Url.Encode(hashedNonceAsBytes);
jsonToken.Header.Remove("nonce");
jsonToken.Header.Add("nonce", hashedNonce);
header = tokenHandler.WriteToken(jsonToken).Split('.')[0];
jsonToken = tokenHandler.ReadJwtToken($"{header}.{payload}.{signature}");
}
}
return jsonToken;
}
};
IdentityModelEventSource.ShowPII = true;
var handler = new JwtSecurityTokenHandler();
var principal = handler.ValidateToken(accessToken, validationParameters, out var token);
return principal != null;
}
catch (Exception ex)
{
return false;
}
}
return false;
}
private void HandleUnauthorizedRequest(HttpActionContext actionContext)
{
// Return 401 Unauthorized response
actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
}
private SecurityKey[] GetSigningKeys(string domain)
{
var jwksUrl = $"https://{domain}/.well-known/jwks.json";
var jwksJson = new WebClient().DownloadString(jwksUrl);
var jwks = new JsonWebKeySet(jwksJson);
return jwks.Keys.ToArray();
}
}
}
这样就可以在用户访问每一个后台API的时候根据AccsessToken鉴权了
public class OrderStatusController : BaseController
{
[JwtAuthentication]
[HttpPost, Route("api/eta")]
public async Task<IHttpActionResult> EstimatedTimeToArrival([FromBody] ETARequest request)
{
......