ServiceStack Попытка создать свой собственный OpenIdOAuthProvider, но VS 2017 говорит, что сборка 5.0.0.0 отсутствует

Пытаюсь создать свой собственный поставщик OpenId Auth, который будет указывать на службу IdentityServer, но не может найти OpenIdOAuthProvider в сборке ServiceStack.

VS 2017 говорит

Ошибка CS0012 Тип OAuthProvider определен в сборке, на которую нет ссылок. Вы должны добавить ссылку на сборку «ServiceStack, версия = 5.0.0.0, культура = нейтральная, PublicKeyToken = 02c12cbda47e6587».

public class MyCustomOpenIdOAuthProvider : ServiceStack.Authentication.OpenId.OpenIdOAuthProvider
    {
        //code goes here to point to IdentityServer Realm...
    }

Конечно, у меня есть ссылки на ServiceStack 5.4.1 и ServiceStack.Authentication.OpenId. .Сетевое ядро ​​2.2

Здесь приветствуется любая помощь.


person richardb    schedule 14.12.2018    source источник


Ответы (1)


Пакет ServiceStack.Authentication.OpenId — это проект только .NET Framework, который не поддерживается в .NET Core из-за того, что OpenIdOAuthProvider.cs требует DotNetOpenAuth, который недоступен для .NET Core.

Поскольку вы используете предварительные версии пакетов MyGet версии 5.4.1, вас могут заинтересовать новые NetCoreIdentityAuthProvider, который предоставляет адаптер, который сопоставляет прошедшего проверку подлинности пользователя .NET Core Identity с прошедшим проверку подлинностью сеансом пользователя ServiceStack.

Поэтому, если вы аутентифицируете свое приложение .NET Core с помощью IdentityServer, тогда аутентифицированный пользователь должен сопоставляться с Authenticated UserSession при доступе к ServiceStack Services.

Пример API СС

У меня есть несколько замечаний после просмотра вашего примера на GitHub. По сути, поскольку вы решили использовать IdentityServer в качестве поставщика аутентификации, вы удаляете все остальные поставщики аутентификации ServiceStack, кроме NetCoreIdentityAuthProvider:

Plugins.Add(new AuthFeature(() => new AuthUserSession(),
    new IAuthProvider[] {
        new NetCoreIdentityAuthProvider(AppSettings), 
  }));

Который предоставляет адаптер для преобразования из Identity User ClaimsPrincipal в ServiceStack Authenticated UserSession (и наоборот).

Если вы используете NetCoreIdentityAuthProvider, вам также следует удалить альтернативную реализацию IdentityServerAuthFeature, чтобы вы применяли только одно решение для интеграции с аутентификацией Identity Server:

// this.Plugins.Add(new IdentityServerAuthFeature() // remove...

Поскольку Identity Server использует JWT для заполнения ClaimsPrincipal пользователя, он не использует ClaimTypes.NameIdentifier для указания того, что использовать для идентификатора сеанса. У JWT обычно есть "sub" утверждение для идентификации принципала, который тема JWT, которая заполняется в ServiceStack AuthUserSession.Id и AuthUserSession.Type, будет заполнена «sub», чтобы указать тип сеанса с проверкой подлинности и то, что sub JWT (обычно идентификатор пользователя) используется в сеансе Id.

Вы сможете использовать конфигурацию NetCoreIdentityAuthProvider по умолчанию для аутентификации с помощью JWT Identity Server, которые аутентифицируют пользователя, как это сделано в ваш первый звонок в RequestTokenAsync_CallResourceOwnerFlow():

var response = await client.RequestPasswordTokenAsync(new PasswordTokenRequest
{
    Address = disco.TokenEndpoint,

    ClientId = "roclient",
    ClientSecret = "secret",

    UserName = "bob",
    Password = "password",

    Scope = "apiMB openid",
});

Который вы можете проверить с помощью декодирования JWT в jwt.io, вот полезной нагрузке пример токена, который я получил по этому запросу:

{
  "nbf": 1545170425,
  "exp": 1545174025,
  "iss": "http://127.0.0.1:65048",
  "aud": [
    "http://127.0.0.1:65048/resources",
    "apiMB"
  ],
  "client_id": "roclient",
  "sub": "2",
  "auth_time": 1545170425,
  "idp": "local",
  "scope": [
    "openid",
    "apiMB"
  ],
  "amr": [
    "pwd"
  ]
}

Который, как мы видим, содержит "sub" "2", который является Идентификатор пользователя Боба:

new TestUser
{
    SubjectId = "2",
    Username = "bob",
    Password = "password",
    IsActive = true
}

Ваш второй запрос на клиент:

var response = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
{
    Address = disco.TokenEndpoint,

    ClientId = "client",
    ClientSecret = "secret",
    Scope = "apiMB"
});

Какие не содержит объект в его JWT, но вместо этого заполняется только:

{
  "nbf": 1545170914,
  "exp": 1545174514,
  "iss": "http://127.0.0.1:65048",
  "aud": [
    "http://127.0.0.1:65048/resources",
    "apiMB"
  ],
  "client_id": "client",
  "scope": [
    "apiMB"
  ]
}

В этом случае ServiceStack аутентифицирует его как клиента, где AuthUserSession.Type будет заполнен client_id, а сеанс Id будет заполнен client.

По умолчанию ServiceStack разрешает аутентификацию с помощью любого аутентифицированного client_id (который проверяется Identity Server до того, как он достигает ServiceStack). Если вместо этого вы хотите ограничить доступ к ServiceStack Services только подмножеству клиентских приложений, вы можете указать их в RestrictToClientIds, например:

Plugins.Add(new AuthFeature(() => new AuthUserSession(),
    new IAuthProvider[] {
        new NetCoreIdentityAuthProvider(AppSettings) {
            RestrictToClientIds = new List<string> { "client" },
        }, 
  }));

Где ServiceStack разрешает доступ только клиентским приложениям с идентификатором client client_id.

Аудитории (aud) JWT заполняются в AuthUserSession Audiences, в то время как области действия JWT заполняются в свойстве Scopes, а все другие необработанные свойства из JWT — в словаре сеансов Meta.

Эти изменения в NetCoreIdentityAuthProvider доступны только в последней версии 5.4.1 на MyGet. Если у вас уже была версия 5.4.1, вам необходимо очистить кеш NuGet, чтобы получить последнюю версию 5.4.1 из MyGet:

$ nuget locals all -clear

Проблемы проверки кода

Не связано с аутентификацией, но я заметил несколько проблем в вашем коде, где для чтения AppSettings из вашего приложения вы должны просто использовать свойство AppSettings вместо создания нового экземпляра:

// var appSettings = new AppSettings(); // Use base.AppSettings instead

Вы также можете получить доступ к IConfiguration .NET Core с помощью:

var configuration = ((NetCoreAppSettings) AppSettings).Configuration;

Вместо того, чтобы пытаться воссоздать его с помощью:

//IConfigurationRoot configuration = new ConfigurationBuilder()
//       .SetBasePath(Directory.GetCurrentDirectory())
//       .AddJsonFile("appsettings.json")
//       .Build();
person mythz    schedule 14.12.2018
comment
Спасибо. Не совсем уверен, что я делаю неправильно, но я могу получить нормальный безопасный API и атрибут [Authorize] для работы, но попытка подключить ServiceStack с ним просто продолжает давать мне Unauthorized. - person richardb; 17.12.2018
comment
@richardb Если вы можете собрать небольшое отдельное приложение на GitHub, показывающее проблему, я могу взглянуть. - person mythz; 17.12.2018
comment
Цените это - я посмотрю, что я могу сделать. Не знаю, как подключаемый модуль должен искать этот NetCoreIdentityAuthProvider. Тем временем я также пробовал IdentityServerAuthFeature, но без радости. - person richardb; 17.12.2018
comment
Демо-репозиторий здесь показывает, чего я пытаюсь/не могу достичь. Цените любую помощь. github.com/richardbartley/SSApi - person richardb; 18.12.2018
comment
Хорошо, это отличный ответ, и он работает. Спасибо за это. Мы собираемся начать важный проект, и мы получим за это подписку. Спасибо еще раз. - person richardb; 20.12.2018
comment
@richardb рад это слышать! Кстати, я обновил ответ последними изменениями с поддержкой клиентского приложения client_id JWT, поэтому вам не нужно специальное сопоставление и вы можете просто использовать значение по умолчанию new NetCoreIdentityAuthProvider(AppSettings). - person mythz; 20.12.2018