Контекстная информация
Я создаю прототип WebApp, который я хочу интегрировать в Quickbooks Online.
Это WebApp, в свою очередь, будетпредложить варианты для вызова WebApi, который будет отвечать за запросы к WebApi Quickbooks Online.
Для этого я зарегистрировал службы Identity, чтобы мне было проще входить в систему и т. д.
Теперь, похоже, я запутался между индивидуальной учетной записью (IdentityUser) и ClaimsIdentity.
Вход в систему
Когда я щелкаю опцию «Вход в систему» в верхнем меню, меня корректно перенаправляют на экран онлайн-аутентификации Quickbooks, где:
- Я ввожу свои учетные данные пользователя
- Я выбираю компанию, которую хочуиспользуйте
- Я разрешаю WebApp получить доступ к необходимым областям
При обратном вызове я выполняю запрос к конечной точке информации о пользователе и извлекаю всю необходимую информацию о пользователе.
- sub
- GivenName
- familyName
- email
- emailVerified
И
- ClaimsIdentity.IsAuthenticated == true
Итак, я создаю список утверждений для ClaimsPrincipal.Identity, который только что был аутентифицирован извне, и пытаюсь войти в него.
var result = JsonConvert.DeserializeObject<Dictionary<string, string>>(response);
var user = (ClaimsIdentity)context.Principal.Identities.Single(claimsIdentity => claimsIdentity.AuthenticationType == "ecm-qbo");
user.AddClaim(new Claim(type: ClaimTypes.Name, result["givenName"]));
result.ToList().ForEach(kvp => {
user.AddClaim(new Claim(type: kvp.Key, value: kvp.Value, valueType: null, issuer: "qbo", originalIssuer: "qbo", subject: user));
});
Но я получаю эту ошибку, когда мой процесс подписания завершен.
Что я могу сделать, чтобы избежать этого, илиисправить это так, чтобы он подписал моего пользователя?
Пример кода
public void ConfigureServices(IServiceCollection services) {
services.Configure<CookiePolicyOptions>(options => {
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.ConfigureApplicationCookie(o => {
o.Cookie.Name = "auth_cookie";
o.Cookie.SameSite = SameSiteMode.None;
o.Events.OnRedirectToLogin = context => {
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
return Task.CompletedTask;
};
});
services.AddAuthentication(o => {
o.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddOAuth("qbo", "qbo", o => {
o.CallbackPath = new PathString("/signin-qbo");
o.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub");
o.ClaimActions.MapJsonKey(ClaimTypes.Email, "email");
o.ClaimActions.MapJsonKey(ClaimTypes.GivenName, "givenName");
o.ClaimActions.MapJsonKey(ClaimTypes.Surname, "familyName");
o.ClaimActions.MapJsonKey(ClaimTypes.Name, "givenName");
o.ClientId = Configuration["ecm.qbo.client-id"];
o.ClientSecret = Configuration["ecm.qbo.client-secret"];
o.SaveTokens = true;
o.ClaimsIssuer = "ecm-qbo";
o.Scope.Add("openid");
o.Scope.Add("profile");
o.Scope.Add("email");
o.Scope.Add("com.intuit.quickbooks.accounting");
o.AuthorizationEndpoint = Configuration["ecm.qbo.authorization-endpoint"];
o.TokenEndpoint = Configuration["ecm.qbo.token-endpoint"];
o.UserInformationEndpoint = Configuration["ecm.qbo.user-info-endpoint"];
o.Events.OnCreatingTicket = async context => {
var companyId = context.Request.Query["realmid"].FirstOrDefault() ?? throw new ArgumentNullException("realmId");
var accessToken = context.AccessToken;
var refreshToken = context.RefreshToken;
var tokens = context.Properties.GetTokens();
Configuration["ecm.qbo.access-token"] = accessToken;
Configuration["ecm.qbo.refresh-token"] = refreshToken;
Configuration["ecm.qbo.realm-id"] = companyId;
context.Backchannel.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);
context.Backchannel.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await context.Backchannel.GetStringAsync(context.Options.UserInformationEndpoint);
var result = JsonConvert.DeserializeObject<Dictionary<string, string>>(response);
var user = (ClaimsIdentity)context.Principal.Identities.Single(claimsIdentity => claimsIdentity.AuthenticationType == "ecm-qbo");
user.AddClaim(new Claim(type: ClaimTypes.Name, result["givenName"]));
result.ToList().ForEach(kvp => {
user.AddClaim(new Claim(type: kvp.Key, value: kvp.Value, valueType: null, issuer: "qbo", originalIssuer: "qbo", subject: user));
});
await context.HttpContext.SignInAsync(IdentityConstants.ExternalScheme, context.Principal, new AuthenticationProperties {
IsPersistent = false,
RedirectUri = "/"
});
};
});
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<IdentityUser, IdentityRole>()
.AddDefaultUI(UIFramework.Bootstrap4)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}