ServiceStack Попытка создать свой собственный OpenIdOAuthProvider, но VS 2017 говорит, что сборка 5.0.0.0 отсутствует - PullRequest
0 голосов
/ 14 декабря 2018

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

VS 2017 сообщает

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

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

У меня есть ServiceStack 5.4.1 и ServiceStack.Authentication.OpenId, конечно, на которые ссылаются..Net Core 2.2

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

1 Ответ

0 голосов
/ 14 декабря 2018

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

Поскольку вы используете предварительные выпуски v5.4.1 MyGet , вас может заинтересовать новый NetCoreIdentityAuthProvider , который обеспечиваетадаптер, который сопоставляет аутентифицированного пользователя .NET Core Identity с аутентифицированным пользовательским сеансом ServiceStack.

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

Пример SS API

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

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

, который предоставляет адаптер для преобразования из аутентификационного пользователя ClaimsPrincipal в ServiceStack AuthenticatedUserSession (и наоборот).

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

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

Поскольку Identity Server использует JWT для заполнения ClaimsPrincipal пользователя, он не использует ClaimTypes.NameIdentifier, чтобы указать, что использовать для идентификатора сеанса.У JWT обычно есть "sub" Претензия , чтобы идентифицировать принципала, который является предметом JWT, который заполнен в AuthUserSession.Id ServiceStack, и AuthUserSession.Type будет заполнен "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" , который UserId Боба :

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

Ваш 2-й запрос аутентификации является примером аутентификации клиента:

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"
  ]
}

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

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

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

, где ServiceStack разрешит доступ только из клиентских приложений сclient client_id.

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

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

$ nuget locals all -clear

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

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

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

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

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

Вместо попытки воссоздать его с помощью:

//IConfigurationRoot configuration = new ConfigurationBuilder()
//       .SetBasePath(Directory.GetCurrentDirectory())
//       .AddJsonFile("appsettings.json")
//       .Build();
...