Попытка использовать идентификационный сервер 4 для аутентификации в asp.net core 2.2 с приложением angular 7.
oidc-login-redirect.html
<script src="https://cdnjs.cloudflare.com/ajax/libs/oidc-client/1.5.4/oidc-client.min.js"></script>
<script>
var config = {
userStore: new Oidc.WebStorageStateStore({ store: window.localStorage })
};
var mgr = new Oidc.UserManager(config);
mgr.signinRedirectCallback().then(() => {
window.history.replaceState({},
window.document.title,
window.location.origin);
window.location = "/";
}, error => {
console.error(error);
});
</script>
Сервисный код Angular Auth
export class AuthServiceJwt implements CanActivate {
_userManager: UserManager;
_user: User;
constructor(public router: Router) {
//Log.logger = console;
var config = {
authority: environment.authority,
client_id: environment.client_id,
redirect_uri: `${environment.client_root_url}assets/oidc-login-redirect.html`,
scope: environment.scope,
response_type: environment.response_type,
post_logout_redirect_uri: `${environment.client_root_url}?postLogout=true`,
userStore: new WebStorageStateStore({ store: window.localStorage }),
automaticSilentRenew: true,
silent_redirect_uri: `${environment.client_root_url}assets/silent-redirect.html`
};
this._userManager = new UserManager(config);
this._userManager.getUser().then(user => {
if (user && !user.expired) {
this._user = user;
//this.loadSecurityContext();
}
});
this._userManager.events.addUserLoaded(args => {
this._userManager.getUser().then(user => {
this._user = user;
//this.loadSecurityContext();
});
});
}
login(): Promise<any> {
return this._userManager.signinRedirect();
}
}
Environment.ts
export const environment = {
authority: 'https://localhost:44305/',
client_id: 'mero-rental-angular-client',
response_type: 'id_token token',
scope: 'openid mero-rental-client-api profile',
client_root_url: 'http://localhost:4200/'
}
Код на стороне сервера. CustomProfileService.cs
public class CustomProfileService : IProfileService
{
private readonly IUserClaimsPrincipalFactory<ApplicationUserViewModel> _claimsFactory;
private readonly UserManager<ApplicationUserViewModel> _userManager;
public CustomProfileService(UserManager<ApplicationUserViewModel> userManager, IUserClaimsPrincipalFactory<ApplicationUserViewModel> claimsFactory)
{
_userManager = userManager;
_claimsFactory = claimsFactory;
}
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var sub = context.Subject.GetSubjectId();
var user = await _userManager.FindByIdAsync(sub);
var principal = await _claimsFactory.CreateAsync(user);
var claims = principal.Claims.ToList();
if (user.Email == "admin@identity.localhost")
{
claims.Add(new Claim(JwtClaimTypes.Role, "Admin"));
}
context.IssuedClaims = claims;
}
public async Task IsActiveAsync(IsActiveContext context)
{
var sub = context.Subject.GetSubjectId();
var user = await _userManager.FindByIdAsync(sub);
context.IsActive = user != null;
}
}
Startup.cs
public void ConfigureServices (IServiceCollection services) {
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUserViewModel, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddTransient<IProfileService, CustomProfileService>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
var builder = services.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
})
.AddInMemoryIdentityResources(GetIdentityResources())
.AddInMemoryApiResources(GetApiResources())
.AddInMemoryClients(GetClients())
.AddAspNetIdentity<ApplicationUserViewModel>()
.AddProfileService<CustomProfileService>();
builder.AddDeveloperSigningCredential();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCors(builder =>
{
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
app.UseIdentityServer();
app.UseAuthentication();
}
класс конфигурации
public partial class Startup
{
public IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource( ConstantValue.ClientDashApi, ConstantValue.ClientApi)
};
}
public IEnumerable<Client> GetClients()
{
var client = new List<Client>
{
new Client
{
ClientId = ConstantValue.ClientId,
ClientName = ConstantValue.ClientName,
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RequireConsent = false,
RedirectUris = { string.Format("{0}/{1}", Configuration["IdentityServerUrls:ClientUrl"], "assets/oidc-login-redirect.html"), string.Format("{0}/{1}", Configuration["IdentityServerUrls:ClientUrl"], "assets/silent-redirect.html") },
PostLogoutRedirectUris = { string.Format("{0}?{1}", Configuration["IdentityServerUrls:ClientUrl"] , "postLogout=true") },
AllowedCorsOrigins = { Configuration["IdentityServerUrls: ClientUrl"] },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
ConstantValue.ClientDashApi
},
IdentityTokenLifetime=120,
AccessTokenLifetime=120
},
};
return client;
}
public IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile()
};
}
}
Постоянное значение
public static class ConstantValue
{
public const string ClientId = "mero-rental-angular-client";
public const string ClientName = "mero-rental";
public const string ClientDashApi = "mero-rental-client-api";
public const string ClientApi = "Mero Rental Client API";
}
Appsetting.json
"IdentityServerUrls": {
"Authority": "https://localhost:5002/",
"ClientUrl": "http://localhost:4200"
}
Я могу успешно войти в систему и увидеть токен jwt с кодом носителя.Но в браузере продолжает появляться сообщение об ошибке, как показано ниже.
При декодировании изображения на сайте JWT.IO обнаружена приведенная ниже информация.
Выполнено небольшое исследование - https://github.com/IdentityServer/IdentityServer4/issues/1194 https://github.com/IdentityServer/IdentityServer4/issues/1249 https://github.com/IdentityServer/IdentityServer4/issues/1608 http://docs.identityserver.io/en/latest/endpoints/userinfo.html
Ошибки
GET https://localhost:44305/connect/userinfo net::ERR_INVALID_HTTP_RESPONSE
oidc-login-redirect.html:13 Error: Network Error
at XMLHttpRequest.s.onerror (oidc-client.min.js:3)
mgr.signinRedirectCallback.then.error @ oidc-login-redirect.html:13
Promise.then (async)
(anonymous) @ oidc-login-redirect.html:7