我已经构建了一个 ASP.net 核心单租户 Web API,它需要来自 Azure 的令牌,我还通过react构建了一个单租户 SPA,它使用 Azure 通过 MSAL-Brower 登录。我想在登录时使用从 azure 提供的令牌来验证我的客户端 SPA 以调用我的 API。令牌请求成功返回,但是当我去获取时,我的 api 上收到一个错误,指出
不匹配:validationParameters.ValidAudience:'System.String'或validationParameters.ValidAudiences:'System.String'。
我通过 MSAL 客户端方法AcquireTokenSilent请求了一个令牌,该令牌具有在 Azure 上建立的权限范围。我已经尝试过了,我已经在客户端和 Web API 中更改了 ClientId 和 ResourceId。
const PostToDataBase = () => {
const authenticationModule: AzureAuthenticationContext = new AzureAuthenticationContext();
const account = authenticationModule.myMSALObj.getAllAccounts()[0]
const endpoint = {
endpoint:"https://localhost:44309/api/values",
scopes:[], // redacted for SO
resourceId : "" // redacted for SO
}
async function postValues(value:string){
if(value.length < 1){
console.log("Value can not be null!")
return;
}
console.log(account)
if(account ){
console.log("acquiring token")
authenticationModule.myMSALObj.acquireTokenSilent({
scopes: endpoint.scopes,
account: account
}).then(response => {
console.log("token acquired posting to server")
const headers = new Headers();
const bearer = `Bearer ${response.accessToken}`;
headers.append("Authorization", bearer);
headers.append("Content-Type", "'application/json'")
const options = {
method: "POST",
headers: headers,
bodyInit: JSON.stringify(value)
};
return fetch(endpoint.endpoint, options)
.then(response => console.log(response))
.catch(error => console.log(error));
}).catch(err => {
console.error(err)
if(err instanceof InteractionRequiredAuthError){
if(account ){
authenticationModule.myMSALObj.acquireTokenPopup({
scopes: endpoint.scopes
}).then(response => {
const headers = new Headers();
const bearer = `Bearer ${response.accessToken}`;
headers.append("Authorization", bearer);
const options = {
method: "POST",
headers: headers,
body: value
};
return fetch(endpoint.endpoint, options)
.then(response => response.json())
.catch(error => console.log(error));
}).catch(err => console.error(err))
}
}
})
}
}
async function getValues(){
console.log(account)
if(account ){
console.log("acquiring token")
authenticationModule.myMSALObj.acquireTokenSilent({
scopes: endpoint.scopes,
account: account
}).then(response => {
console.log("token acquired posting to server")
const headers = new Headers();
const bearer = `Bearer ${response.accessToken}`;
headers.append("Authorization", bearer);
headers.append("Content-Type", "'application/json'")
const options = {
method: "GET",
headers: headers
};
return fetch(endpoint.endpoint, options)
.then(response => response.json())
.then(res => setValues(res))
.catch(error => console.log(error));
}).catch(err => {
console.error(err)
if(err instanceof InteractionRequiredAuthError){
if(account ){
authenticationModule.myMSALObj.acquireTokenPopup({
scopes: endpoint.scopes
}).then(response => {
const headers = new Headers();
const bearer = `Bearer ${response.accessToken}`;
headers.append("Authorization", bearer);
const options = {
method: "GET",
headers: headers,
};
return fetch(endpoint.endpoint, options)
.then(response => response.json())
.then(res => setValues(res))
.catch(error => console.log(error));
}).catch(err => console.error(err))
}
}
})
}
}
const [values, setValues] = useState([]);
const [inputValue, setInput] = useState("");
useEffect(() => {
// async function getinit(){
// const values = await fetch("https://localhost:44309/api/values")
// .then(res => res.json())
// .catch(e =>
// console.error(e))
// setValues(values)
// console.log(values)
// }
getValues()
}, [ getValues])
return (
<div>
{values === undefined ? <p>no values to show</p> :
values.map((n,i)=>( <p key={i}>{n}</p>))}
<form>
<input name="inputValues" value={inputValue} onChange={(e)=> setInput(e.target.value)} required></input>
</form>
<button onClick={() => postValues(inputValue)}>Post to Server</button>
</div>
)
}
export default PostToDataBase
这是调用api的功能组件,只有在用户登录后才能访问该页面。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Authentication.JwtBearer;
namespace McQuillingWebAPI
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//change to client url in production
services.AddCors(o => o.AddPolicy("MyPolicy", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(opt =>
{
opt.Audience = Configuration["AAD:ResourceId"];
opt.Authority = $"{Configuration["AAD:Instance"]}{Configuration["AAD:TenantId"]}";
});
services.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors("MyPolicy");
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
这是我的启动类,我在其中配置了用于身份验证的中间件
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Identity.Web.Resource;
namespace McQuillingWebAPI.Controllers
{
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
return "value";
}
// POST api/values
[Authorize]
[HttpPost]
public IActionResult Post([FromBody] string value)
{
return Ok("Posted");
}
// PUT api/values/5
[HttpPut("{id}")]
public void Put(int id, [FromBody] string value)
{
}
// DELETE api/values/5
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
}
这是我正在测试身份验证的生成控制器之一