#c# #reactjs #asp.net-core #single-page-application #identityserver4
#c# #reactjs #asp.net-core #одностраничное приложение #identityserver4
Вопрос:
Привет, я унаследовал такую систему:
Api и множество интерфейсов (spa) у них общее меню со ссылками для перехода друг к другу, но это разные приложения react с разными URL-адресами. И Azure Active Directory для аутентификации API защищен токеном на предъявителя.
Что-то вроде этого:
Теперь у меня есть требования к авторизации с пользовательскими разрешениями, которые бизнесмены хотят назначить каждому пользователю, для действий, которые они могут выполнять или нет, и для видимости.
Я хочу использовать Identity4Server с active directory в качестве поставщика открытых идентификаторов. Затем используйте API-интерфейс поставщика, чтобы получить пользовательские разрешения и поместить эти разрешения в утверждения. Затем в Api внедряются политики, требующие указания ролей и утверждений для выполнения спецификаций разрешений.
Что-то вроде этого:
Конфигурация Identity4Server:
services.AddAuthentication()
.AddOpenIdConnect("oidc", "OpenID Connect", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.SignOutScheme = IdentityServerConstants.SignoutScheme;
options.SaveTokens = true;
options.RequireHttpsMetadata = false;
options.Authority = "https://login.microsoftonline.com/tenant/";
options.ClientId = "ClientId";
options.ClientSecret = "ClientSecret";
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role"
};
});
API:
services
.AddAuthentication(configure =>
{
configure.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
configure.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Audience = "api";
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
});
var clientsPolicy = new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes("Bearer")
.AddRequirements(new ClaimsAuthorizationRequirement("ClientsModule", new[] { "1" }))
.RequireRole("Admin")
.Build();
services.AddAuthorization(options =>
{
options.AddPolicy("Clients", clientsPolicy);
});
Для приложений react я использую этот npm «oidc-client»: «1.7.0» и аналогичный подход к https://medium.com/@franciscopa91/how-to-implement-oidc-authentication-with-react-context-api-and-react-router-205e13f2d49
И конфигурация клиентов такова: (Поставщик очень похож, единственное, что меняется, это url localhost: 3001)
export const IDENTITY_CONFIG = {
authority: "http://localhost:5000",
clientId: "fronts",
redirect_uri: "http://localhost:3000/signin-oidc",
login: "http://localhost:5000/login",
automaticSilentRenew: false,
loadUserInfo: false,
silent_redirect_uri: "http://localhost:3000/silentrenew",
post_logout_redirect_uri: "http://localhost:3000/signout-callback-oidc",
audience: "fronts",
responseType: "id_token token",
grantType: "password",
scope: "openid api",
webAuthResponseType: "id_token token"
};
Если пользователь входит в систему на стороне клиентов (localhost: 3000), а затем переходит к поставщикам (localhost: 3001), он не должен входить в систему снова. Для достижения этой цели я настраиваю все интерфейсы с одним и тем же идентификатором клиента, но я не знаю, правильно ли это сделать. Теперь мой класс конфигурации на сервере идентификации:
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
ClientId = "fronts",
ClientSecrets =
{
new Secret("secret".Sha256())
},
ClientName = "All fronts",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = { "http://localhost:3000/signin-oidc", "http://localhost:3001/signin-oidc" },
PostLogoutRedirectUris = { "http://localhost:3000/signout-callback-oidc", "http://localhost:3001/signout-callback-oidc" },
AllowedCorsOrigins = { "http://localhost:3000", "http://localhost:3001" },
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api"
}
}
};
}
Как вы думаете, эта конфигурация является правильным способом сделать это или есть лучший подход?
Ответ №1:
Вы упомянули
много разных приложений react с разными URL-адресами
но в вашем фрагменте кода я вижу только Clients(localhost:3000)
.
В любом случае, спецификация протокола говорит нам регистрировать столько клиентов, сколько нам нужно. SSO является основной обязанностью поставщика удостоверений.
Вам просто нужно добавить RequireConsent = false;
к вашему клиенту def в IdSrv, чтобы избежать дополнительного непреднамеренного взаимодействия с пользователем.
Кроме того, в настоящее время рекомендуемым потоком аутентификации для spa-ов является «code pkce». Вы можете взглянуть на эту статью, чтобы получить подробную информацию о переходе.
Комментарии:
1. привет, d_f спасибо за ваш ответ. Я посмотрю на статью. Вы также можете увидеть поставщиков (localhost: 3001) с другим URL. Я собираюсь обновить вопрос с помощью конфигурации идентификатора spa. Также проблема заключается в том, что не регистрируется много клиентов, я могу зарегистрировать 1 клиента на сайт spa, проблема в том, что если я войду на один сайт и перейду на другой сайт, мне не нужно снова входить в систему.
2. Конечно! Как я уже упоминал, основная задача IdP — создать сеанс для пользователя и выполнять вход в систему автоматически для каждого следующего приложения, действуя от имени того же пользователя.
3. Вам нужно добавить
RequireConsent = false;
к вашему клиенту def в IdSrv, чтобы избежать дополнительного непреднамеренного взаимодействия с пользователем. Добавит это к ответу.4. Еще одна небольшая вещь:
ClientSecret
не требуется для неявного типа предоставления nor Code PKCE.ClientSecret
должно сохраняться тайно, в то время как код приложений на основе браузера является общедоступным по дизайну.