У меня есть типичный проект Blazor WASM, сервер, клиент и общий доступ. Аутентификация с IdentityServer настроена и работает правильно. Я получаю JWT, когда вхожу в систему с пользователем и могу получить документ обнаружения.
Помимо обычных пользователей, я хочу подключать устройства. Эти устройства не являются пользователями, поэтому создавать пользователя для каждого устройства кажется неправильным. Если я создам пользователя, я могу войти в систему и получить токен. Но я добавил InMemoryClients, поэтому я предполагал, что могу войти в систему как клиент с идентификатором / секретом, используя конечную точку аутентификации устройства в документе обнаружения.
Я добавил консольное приложение, работающее на устройстве. Но аутентификация не возвращает invalid_client.
В серверном приложении я определил Client и ApiScope:
public static IEnumerable<ApiScope> ApiScopes =>
new List<ApiScope>
{
new ApiScope("api", "My API")
};
public static IEnumerable<IdentityServer4.Models.Client> Clients =>
new List<IdentityServer4.Models.Client>
{
new IdentityServer4.Models.Client
{
ClientId = "device",
// no interactive user, use the clientid/secret for authentication
AllowedGrantTypes = GrantTypes.ClientCredentials,
// secret for authentication
ClientSecrets =
{
new Secret("secret")
},
// scopes that client has access to
AllowedScopes = { "api" }
}
};
Они добавляются с помощью функций AddInMemory в методе Startup.Configure:
services.AddIdentityServer()
.AddInMemoryApiScopes(Config.ApiScopes)
.AddInMemoryClients(Config.Clients)
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
options.IdentityResources["openid"].UserClaims.Add("name");
options.ApiResources.Single().UserClaims.Add("name");
options.IdentityResources["openid"].UserClaims.Add("role");
options.ApiResources.Single().UserClaims.Add("role");
});
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://localhost:44316";
options.Audience = "api";
})
.AddIdentityServerJwt();
В консольном приложении я отправляю DeviceAuthenticationRequest:
static IDiscoveryCache _cache = new DiscoveryCache("https://localhost:44316");
var disco = await _cache.GetAsync();
if (disco.IsError) throw new Exception(disco.Error);
var client = new HttpClient();
response = await client.RequestDeviceAuthorizationAsync(new DeviceAuthorizationRequest
{
//Address = disco.TokenEndPoint, // same result
Address = disco.DeviceAuthorizationEndpoint,
ClientId = "device",
ClientSecret = "secret",
Scope = "api"
});
Ответ в клиенте содержит ошибку invalid_client. И сервер тоже жалуется:
IdentityServer4.Validation.ClientSecretValidator: Error: No client with id 'client' found. aborting
Надеюсь, мой вопрос ясен, заранее спасибо.
РЕДАКТИРОВАТЬ Очевидно, что ошибка была опечаткой. Но мне удалось это исправить, изменив AllowedGrantTypes на:
AllowedGrantTypes = { GrantTypes.ClientCredentials, GrantTypes.DeviceFlow };
Тем не мение! Мне пришлось удалить авторизацию api, нужно выяснить, как добавить ее обратно:
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
options.IdentityResources["openid"].UserClaims.Add("name");
options.ApiResources.Single().UserClaims.Add("name");
options.IdentityResources["openid"].UserClaims.Add("role");
options.ApiResources.Single().UserClaims.Add("role");
});
И вместо указания параметров и добавления JwtBearer:
//services.AddAuthentication("Bearer")
// .AddJwtBearer("Bearer", options =>
// {
// options.Authority = "https://localhost:44316";
// options.Audience = "api";
// })
// .AddIdentityServerJwt();
У меня только вот это:
services.AddAuthentication()
.AddIdentityServerJwt();