oidc-client를 사용하는 Angular 클라이언트가있는 Identity Server 4 응용 프로그램이 있습니다. 문제는 생산에서 방법
addUserSignedOut
입니다
클라이언트에 로그인 한 후에 전화가 멈추지 않습니다. 로컬에서 테스트하여 정상적으로 작동합니다.
배포시 존재하지 않는 쿠키와 관련된 문제 일 수 있습니다. 나는
checksession
를 확인
와이즈 비즈
방법과 쿠키가 비어 있습니다 (
getCookies()
)
) 로그인 후 해결 방법에 대해 잘 알고 있습니까?
이것은 내 IDP 코드입니다 :
document.cookie = ""
IDP 로그 아웃 컨트롤러 :
public void ConfigureServices(IServiceCollection services)
{
string connectionString = Configuration.GetConnectionString("DefaultConnection");
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
services.AddDataProtection()
.AddKeyManagementOptions(dp => dp.NewKeyLifetime = TimeSpan.FromDays(90));
//.PersistKeysToAzureBlobStorage(new Uri("<blobUriWithSasToken>"))
//.ProtectKeysWithAzureKeyVault("<keyIdentifier>", "<clientId>", "<clientSecret>");
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString));
services.AddIdentity<ApplicationUser, IdentityRole>(options => {
options.Password.RequiredLength = 6; // Passwords must be at least 6 characters
options.Password.RequireLowercase = true; // Passwords must have at least one lowercase ('a'-'z')
options.Password.RequireUppercase = true; // Passwords must have at least one uppercase ('A'-'Z')
options.Password.RequireDigit = true; // Passwords must have at least one digit ('0'-'9')
options.Password.RequireNonAlphanumeric = true; // Passwords must have at least one non alphanumeric character
options.Password.RequiredUniqueChars = 1; // Passwords must use at least 1 different characters
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddMvc().SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_1).AddXmlSerializerFormatters();
services.Configure<IISOptions>(iis =>
{
iis.AuthenticationDisplayName = "Windows";
iis.AutomaticAuthentication = false;
});
services.AddTransient<IProfileService, ProfileService>();
var builder = services.AddIdentityServer(
options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
}
)
// this adds the config data from DB (clients, resources)
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b =>
b.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
})
// this adds the operational data from DB (codes, tokens, consents)
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b =>
b.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
// this enables automatic token cleanup. this is optional.
options.EnableTokenCleanup = true;
});
// Add SAML SSO services.
services.AddSaml(Configuration.GetSection("SAML"));
builder.Services.Configure<SecurityStampValidatorOptions>(opts =>
{
opts.OnRefreshingPrincipal = SecurityStampValidatorCallback.UpdatePrincipal;
});
services.AddAuthentication(options => {
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies", opts =>
{
opts.SlidingExpiration = true;
opts.ExpireTimeSpan = TimeSpan.FromMinutes(15);
});
if (Environment.IsDevelopment() || Environment.EnvironmentName == "local" )
{
builder.AddDeveloperSigningCredential();
}
else
{
X509Certificate2 cert = null;
using (X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
certStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCollection = certStore.Certificates.Find(
X509FindType.FindByThumbprint,
Configuration.GetSection("Certificate").GetValue<string>("thumbprint"),
false);
// Get the first cert with the thumbprint
if (certCollection.Count > 0)
{
cert = certCollection[0];
Log.Logger.Information($"Successfully loaded cert from registry: {cert.Thumbprint}");
}
}
// Fallback to local file for development
if (cert == null)
{
throw new Exception("Cannot find any Certificate");
}
builder.AddSigningCredential(cert);
}
}
public void Configure(IApplicationBuilder app)
{
if (Environment.IsDevelopment() || Environment.EnvironmentName == "local")
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();//SSO
}
app.UseHttpsRedirection();//SSO
app.UseStaticFiles();
app.UseCookiePolicy();//SSO
app.UseIdentityServer();
app.UseAuthentication();//SSO
app.UseSaml();// Use SAML middleware.
app.UseMvcWithDefaultRoute();
}
SAML 로그 아웃 :
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout(LogoutInputModel model)
{
// build a model so the logged out page knows what to display
var vm = await BuildLoggedOutViewModelAsync(model.LogoutId);
if (User?.Identity.IsAuthenticated == true)
{
// Request logout at the service provider(SAML).
await InitiateSingleLogout();
// delete local authentication cookie
await _signInManager.SignOutAsync();
// raise the logout event
await _events.RaiseAsync(new UserLogoutSuccessEvent(User.GetSubjectId(), User.GetDisplayName()));
}
if (vm.PostLogoutRedirectUri != null) {
return Redirect(vm.PostLogoutRedirectUri);
}
// since we don't have a valid context, then we just go back to the home page
return Redirect("~/");
}
앵귤러 클라이언트 oidc 클라이언트 설정 :
private async Task InitiateSingleLogout()
{
var ssoState = await _samlIdentityProvider.GetStatusAsync();
if (await ssoState.CanSloAsync())
{
// Request logout at the service provider(s).
await _samlIdentityProvider.InitiateSloAsync();
}
}
로그 아웃 이벤트 처리 :
const settings: any = {
authority: `${environment.identity_server_url}`,
client_id: 'js',
redirect_uri: `${environment.login_redirect}/signin-oidc`,
response_type: 'id_token token',
scope: 'openid profile salesforce api1',
post_logout_redirect_uri: `${environment.login_redirect}`,
userStore: new WebStorageStateStore({ store: window.localStorage }),
silent_redirect_uri: `${environment.login_redirect}/signin-oidc-silent`,
// automaticSilentRenew: true
};
이것은 사용자가 로그인했는지 확인하고
this.mgr.events.addUserSignedOut(() => {
this.startSigninMainWindow({ external_logout: true })
})
에 전화하는 나의 경비입니다
:
signinRedirect()
이
export class AuthGuardService implements CanActivate {
constructor(
private authService: AuthService
) { }
canActivate() {
const isLoggedIn = this.authService.isLoggedInObs();
isLoggedIn.subscribe(loggedin => {
if (!loggedin) {
this.authService.startSigninMainWindow();
}
});
return isLoggedIn;
}
}
입니다
oidc-client에 대한 모든 논리가있는 클래스.
AuthService
그리고
export class AuthService {
mgr: UserManager = new UserManager(settings);
userLoadededEvent: EventEmitter<User> = new EventEmitter<User>();
currentUser: User;
loggedIn = false;
authHeaders: Headers;
private accountID: string;
private accountToken: string;
private internInfoSubject = new BehaviorSubject<InternUser>(null);
public readonly internInfo$ = this.internInfoSubject
.asObservable()
.pipe(
filter(user => user !== null),
distinctUntilChanged()
);
constructor(
private router: Router,
private internPortalService: InternPortalService,
private apiService: ApiService,
private http: HttpClient
) {
this.mgr.events.addUserSignedOut(() => {
this.startSigninMainWindow({ external_logout: true })
})
}
getUser() {
this.mgr
.getUser()
.then(user => {
console.log('got user', user);
this.currentUser = user;
this.userLoadededEvent.emit(user);
})
.catch(function(err) {
console.log(err);
});
}
startSigninMainWindow(query = {}) {
this.mgr.signinRedirect({extraQueryParams: query});
}
endSigninMainWindow() {
this.mgr
.signinRedirectCallback()
.then(user => {
console.log('signed in', user);
this.currentUser = user;
this.setLocalStorage();
})
.catch(function(err) {
console.log(err);
});
}
endSigninSilentMainWindow() {
this.mgr
.signinSilentCallback()
.then(() => {
console.log('end silent signed in');
})
.catch(function(err) {
console.log(err);
});
}
changePassword(): Observable<any> {
const params = new HttpParams()
.set('userId', this.currentUser.profile.sub)
.set('passwordAction', '2')
.set('redirectUrl', window.location.href);
return this.apiService.getIdentityServer('/Token', params);
}
startSignoutMainWindow() {
this.mgr
.signoutRedirect()
.then(function(resp) {
console.log('signed out', resp);
// setTimeout(5000, () => {
// console.log('testing to see if fired...');
// });
})
.catch(function(err) {
console.log(err);
});
}
isLoggedInObs(): Observable<boolean> {
return observableFrom(this.mgr.getUser()).pipe(
map<User, boolean>(user => {
if (user) {
if (!this.internPortalService.getAccountId()) {
this.currentUser = user;
this.setLocalStorage();
}
return true;
} else {
return false;
}
})
);
}
onSignOut(callback: Function){
this.mgr.events.addUserSignedOut(resp => {
console.log("user signed out");
callback();
});
}
get authenticationInfo(): InternUser {
return this.internInfoSubject.value;
}
private setLocalStorage() {
this.accountID = this.currentUser.profile.account_id;
this.accountToken = this.currentUser.access_token;
this.internPortalService.setAccountId(this.accountID, this.accountToken);
this.internPortalService
.getIntern()
.subscribe(res => this.updateToken(res));
}
updateToken(internUser: any): void {
console.log(internUser);
if (!internUser) {
return;
}
// TODO: Refactor once BE migration is completed
internUser.auth = this.currentUser;
internUser.state_locales = this.internPortalService.getStateLocales(
internUser.state
);
this.internInfoSubject.next(internUser);
this.router.navigate(['/intern-portal']);
}
// TODO: To be removed after QA
public updateLocale(counter: number): void {
const stateList = ['TX', 'MI', 'AZ', 'NC', 'SC', 'FL', 'NV', 'IN'];
const newUser = this.authenticationInfo;
newUser.state = stateList[counter];
newUser.state_locales = this.internPortalService.getStateLocales(
newUser.state
);
console.log(`An user from: ${newUser.state_locales.state} was loaded`);
this.internInfoSubject.next(newUser);
}
logout(): void {
localStorage.clear();
this.internInfoSubject.next(null);
}
}
구성 요소 :
signin-oidc-silent
호스트 앱에서 무한 루프가 발생하는 이유를 모르겠습니다. 실제로 클라이언트를 로컬로 사용하고 호스팅 된 IDP를 가리키면 동일한 무한 루프가 발생합니다.
콘솔에 오류가없고이 경고 만
일부 IDP 로그 :
export class SigninOidcComponent implements OnInit {
private element: any;
constructor(private authService: AuthService) {
}
ngOnInit() {
console.log('init oidc logic');
this.authService.endSigninMainWindow();
}
}
ResponseValidator._processSigninParams: Response was error login_required
-
답변 # 1
관련 자료
- SQL Server Management Studio에서 뷰가 비어있는 원인은 무엇입니까?
- ssis - sql server 데이터 도구 - 데이터 링크 속성 :서버 이름 드롭 다운 비어 있음
- angular - 사용자 세부 사항을 검색하는 Identity Server
- python - SimpleHTTPServer 코드를 동등한 프로덕션 서버로 변경하는 방법
- identityserver4 - 메모리에서 사용자 정의를받는 Identity Server
- 다트 서버에 쿠키를 추가 하시겠습니까?
- identityserver4 - Identity Server 4를 호출하여 로그인 할 때 전자 메일 아이디를 보내는 방법
- node.js - 포트 3000에서 쿠키를 가져 오려고 할 때 쿠키와 서명 된 쿠키가 왜 비어 있습니까?
- Blazor 서버 측에서 쿠키 생성 및 읽기
- java - 자신의 서버에 빈 요청을 보내는 브라우저
- c# - SQL SERVER의 SqlBulkCopy ID
- api - Identity Server 4 Postman 요청 토큰이 작동하지 않음
- c# - identity server 4 windowscryptographicexception - 키 집합이 없습니다
- vue.js - 프로덕션 빌드 후 vue js에서 API에 대한 서버 URL을 읽는 파일 생성
- wso2is - Carbon Admin Portal에서 WSO2 Identity Server의 버전 번호 가져 오기
- node.js - Next js 프로덕션 빌드에 서버의 node_modules 폴더가 필요합니까?
- node.js - 연속 요청에 대해 두 개의 서로 다른 쿠키를 보내는 서버를 처리하는 방법은 무엇입니까?
- identifier - 자동 생성 문제로 인한 SQL Server ID 교체
- OpenCv의 폴더에서 여러 이미지 읽기 (python)
- 파이썬 셀레늄 모든 "href"속성 가져 오기
- git commit - 자식 - 로컬 커밋 된 파일에 대한 변경을 취소하는 방법
- html - 자바 스크립트 - 클릭 후 변경 버튼 텍스트 변경
- JSP에 대한 클래스를 컴파일 할 수 없습니다
- javascript - 현재 URL에서 특정 div 만 새로 고침/새로 고침
- jquery - JavaScript로 현재 세션 값을 얻으시겠습니까?
- javascript - swiperjs에서 정지, 재생 버튼 추가
- vue.js - axios를 사용하여 서버에 이미지를 업로드하는 방법
- python - 문자열에서 특정 문자 제거
마침내
SameSite.None
를 설정할 곳을 찾았습니다. 쿠키는 세션 상태를 확인할 때 브라우저가 IS로 다시 보낼 수 있도록합니다. 내 경우에는ASP.NET Core Identity
를 사용하고 있습니다. 코드는 다음과 같습니다.후 :