Проверьте Azure токен на предъявителя из внешнего интерфейса на Net Базовом бэкэнде WebApi - PullRequest
0 голосов
/ 04 мая 2020

Цель: войти в систему Azure Пользователь AD на веб-интерфейсе с диалоговым окном входа в систему Microsoft. Добавить токен в бэкэнд-запрос. Проверьте токен на бэкэнде, чтобы убедиться, что только авторизованные пользователи могут получить доступ к коду. Сложная часть: проверить вручную, потому что это не единственная аутентификация на месте.

Мне удалось войти в систему и отправить токен, но при проверке я получаю ошибки вроде: IDX10511: Signature validation failed. Keys tried: ...

Вот что у меня пока что:

app.module.ts

@NgModule({
  declarations: [
    AppComponent,
    RestrictedPageComponent
  ],
  imports: [
    HttpClientModule,
    MsalModule.forRoot({
      auth: {
        clientId: '<CLIENT ID>',
      }
    }, {
      consentScopes: [
        'user.read',
        'openid',
        'profile',
      ],
      protectedResourceMap: [
        ['https://localhost:44323/v1/login', ['user.read']], // frontend
        ['https://localhost:5001/api/Login', ['user.read']] // backend
      ]
    }),
    BrowserModule,
    AppRoutingModule
  ],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: MsalInterceptor,
      multi: true
    },
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

login.component.ts

  login() {
    const loginRequest = { scopes: ['https://graph.microsoft.com/User.ReadWrite'] };
    this.authService.loginPopup(loginRequest);
  }

И это, кажется, работает просто отлично. Я могу войти через Microsoft, и MsalInterceptor добавляет токен-носитель в заголовок запроса бэкэнда.

Теперь на бэкэнде я просто хочу убедиться, что токен действителен и что пользователь аутентифицирован корректно.

private JwtSecurityToken Validate(string token)
{
    var stsDiscoveryEndpoint = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration";
    // also tried "https://login.microsoftonline.com/<TENANT ID>/v2.0/.well-known/openid-configuration"

    var openIdConnectConfigurationRetriever = new OpenIdConnectConfigurationRetriever();
    var configManager = new ConfigurationManager<OpenIdConnectConfiguration>(stsDiscoveryEndpoint, openIdConnectConfigurationRetriever);

    var config = configManager.GetConfigurationAsync().Result;

    var validationParameters = new TokenValidationParameters
    {
        IssuerSigningKeys = config.SigningKeys,

        // just for now
        ValidateAudience = false,
        ValidateIssuer = false,
        ValidateLifetime = false
    };

    var tokenHandler = new JwtSecurityTokenHandler();
    IdentityModelEventSource.ShowPII = true;

    token = token.Replace("Bearer ", string.Empty); // weird - the token starts with "Bearer " and is not valid like this
    var result = tokenHandler.ValidateToken(token, validationParameters, out var jwt);

    return jwt as JwtSecurityToken;
}

При вызове tokenHandler.ValidateToken(... я всегда получаю сообщение об ошибке типа IDX10511: Signature validation failed. Keys tried: .... Я больше не уверен, правильно ли я понял и использовал всю концепцию. Чем больше я читаю об использовании Azure токена на предъявителя и валидации, тем больше он меня смущает.

Я могу разобрать токен на http://jwt.io, но подпись всегда недействительна.

Может ли бэкэнд проверить токен без передачи какого-либо общего секрета или идентификатора клиента? Правильный ли это подход для начала?

edit: Я не уверен, использовал ли я правильные конечные точки для вызова внешнего и внутреннего интерфейса и какую роль играют разные конечные точки (например, с идентификатором арендатора или без него) , Было бы здорово, если бы кто-то мог объяснить.

BR Матиас

1 Ответ

2 голосов
/ 04 мая 2020

Похоже, ваш клиент получает токен доступа для Microsoft Graph API. Этот токен предназначен только для MS Graph API, а не для вашего API. Эти токены Graph API также отличаются особым способом построения, и вам не следует пытаться их проверять.

Вместо этого в вашем интерфейсе необходимо указать области действия для вашего API.

      consentScopes: [
        'your-api-client-id-or-app-id-uri/user_impersonation',
        'openid',
        'profile',
      ],
      protectedResourceMap: [
        ['https://localhost:44323/v1/login', ['user.read']], // frontend
        ['https://localhost:5001/api/Login', ['your-api-client-id-or-app-id-uri/user_impersonation']] // backend
      ]

Для этого вам нужно будет go зарегистрировать приложение вашего API в Azure AD, go на вкладке Expose API и добавить туда область. Затем вы берете полный идентификатор области (который включает ваш идентификатор клиента API или URI идентификатора приложения + идентификатор области) и используете его в качестве области при получении токенов. Azure После этого AD должен выдать вам токен, предназначенный для вашего API.

Если вы используете ASP. NET Core, минимальная конфигурация, необходимая для проверки Azure AD токенов: :

// In ConfigureServices
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(o =>
    {
        o.Authority = "https://login.microsoftonline.com/your-tenant-id";
        o.Audience = "your-app-client-id";
    });

// In Configure (between UseRouting and UseEndpoints)
app.UseAuthentication();
app.UseAuthorization();

Теперь в некоторых случаях, если ваш API настроен на получение токенов v1 в Azure AD, токен может содержать идентификатор клиента API или URI идентификатора приложения. В этом случае вы можете настроить несколько допустимых аудиторий:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(o =>
    {
        o.Authority = "https://login.microsoftonline.com/your-tenant-id";
        o.TokenValidationParameters = new TokenValidationParameters
        {
            ValidAudiences = new[]
            {
                "your-api-client-id",
                "your-api-app-id-uri"
            }
        };
    })
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...