我使用了自定义的AuthenticationHandler,当请求localhost:5011/WeatherForecast?_token=123456,总是报错 "IDW10203: The 'scope' or 'scp' claim does not contain scopes 'access_as_user' or was not found" ,为什么会报这个错误,该如何解决它呢?
我是想通过DemoAuthenticationHandler来实现自定义简单的身份验证,就是传入一个发给使用者不公开的_token字符串(不是一个规范的token更像一个加密的密码),验证通过了就可以访问。我使用asp.net core5.0的提供的Identity相关的package如何实现我的这个需求呢
public class DemoAuthenticationOptions : AuthenticationSchemeOptions
public const string Scheme = "Demo";
}
public class DemoAuthenticationHandler : AuthenticationHandler<DemoAuthenticationOptions>
{
public DemoAuthenticationHandler(IOptionsMonitor<DemoAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
: base(options, logger, encoder, clock)
{ }
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!Request.Query.TryGetValue("_token", out var keys))
{
return Task.FromResult(AuthenticateResult.Fail("The authentication process failed."));
}
var key = keys.FirstOrDefault();
if (key == "123456")
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, "My IO")
};
var identity = new ClaimsIdentity(claims, DemoAuthenticationOptions.Scheme);
var identities = new List<ClaimsIdentity> { identity };
var principal = new ClaimsPrincipal(identities);
var ticket = new AuthenticationTicket(principal, DemoAuthenticationOptions.Scheme);
return Task.FromResult(AuthenticateResult.Success(ticket));
}
return Task.FromResult(AuthenticateResult.Fail("The authentication process failed."));
}
}
public static class AuthenticationBuilderExtensions
{
public static AuthenticationBuilder AddDemoAuthentication(this AuthenticationBuilder authenticationBuilder, Action<DemoAuthenticationOptions> options)
{
return authenticationBuilder.AddScheme<DemoAuthenticationOptions, DemoAuthenticationHandler>(DemoAuthenticationOptions.Scheme, options);
}
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddAuthentication(option =>
{
option.DefaultAuthenticateScheme = DemoAuthenticationOptions.Scheme;
option.DefaultChallengeScheme = DemoAuthenticationOptions.Scheme;
})
.AddDemoAuthentication(options => { });
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers().RequireAuthorization(DemoAuthenticationOptions.Scheme);
});
}
}
原来是我自己搞错了,在action里面有一句验证scopes的代码
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
namespace YourNamespace
{
public class DemoAuthenticationOptions : AuthenticationSchemeOptions
{
public const string Scheme = "Demo";
}
public class DemoAuthenticationHandler : AuthenticationHandler<DemoAuthenticationOptions>
{
public DemoAuthenticationHandler(IOptionsMonitor<DemoAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
: base(options, logger, encoder, clock)
{ }
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!Request.Query.TryGetValue("_token", out var keys))
{
return Task.FromResult(AuthenticateResult.Fail("The authentication process failed."));
}
var key = keys.FirstOrDefault();
if (key == "123456")
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, "My IO"),
new Claim("scope", "access_as_user")
};
var identity = new ClaimsIdentity(claims, DemoAuthenticationOptions.Scheme);
var identities = new List<ClaimsIdentity> { identity };
var principal = new ClaimsPrincipal(identities);
var ticket = new AuthenticationTicket(principal, DemoAuthenticationOptions.Scheme);
return Task.FromResult(AuthenticateResult.Success(ticket));
}
return Task.FromResult(AuthenticateResult.Fail("The authentication process failed."));
}
}
public static class AuthenticationBuilderExtensions
{
public static AuthenticationBuilder AddDemoAuthentication(this AuthenticationBuilder authenticationBuilder, Action<DemoAuthenticationOptions> options)
{
return authenticationBuilder.AddScheme<DemoAuthenticationOptions, DemoAuthenticationHandler>(DemoAuthenticationOptions.Scheme, options);
}
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddAuthentication(option =>
{
option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddDemoAuthentication(options => { });
services.AddAuthorization();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "your-issuer",
ValidAudience = "your-audience",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your-secret-key"))
};
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers().RequireAuthorization();
});
}
}
}
这个错误提示是因为你的 AuthenticationHandler 在处理请求时,需要检查请求中是否包含了指定的 scope(作用域),但是在请求中并没有包含该 scope 或者根本没有包含任何 scope,因此导致了该错误。
在使用自定义的 AuthenticationHandler 时,你需要通过实现 HandleAuthenticateAsync 方法来处理请求的身份验证。其中,你可以通过以下代码来获取请求中包含的 scope:
Copy
var scopes = principal.FindFirst("scope")?.Value?.Split(' ');
在这里,principal 是一个 ClaimsPrincipal 对象,它包含了当前请求的身份验证信息。通过 FindFirst 方法获取到了名为 "scope" 的 claim,之后使用 Value 属性获取到了 claim 的值,并使用 Split 方法将其分割成一个字符串数组。在这个数组中,每个元素表示一个 scope。
接下来,你需要检查这个 scope 数组中是否包含了你需要的 scope。比如,如果你需要检查是否包含了 "access_as_user" 这个 scope,可以使用以下代码:
if (scopes == null || !scopes.Contains("access_as_user"))
{
return AuthenticateResult.Fail("The 'access_as_user' scope is required.");
}
这段代码首先检查 scope 数组是否为空,如果为空则表示请求中没有包含任何 scope,因此直接返回身份验证失败。否则,它会使用 Contains 方法检查数组中是否包含了 "access_as_user" 这个 scope。如果没有包含,则认为身份验证失败,并返回错误信息。
因此,如果你在请求中传递的 _token 参数并没有包含 "access_as_user" 这个 scope,就会出现该错误。你需要确保请求中包含了指定的 scope,或者修改你的代码,使其不要要求指定的 scope。
回答整理自chatgpt,如果有帮助麻烦采纳一下,谢谢啦!