본문 바로가기

컴퓨터공학/Boot & Angular

Angular> 로그인 로그아웃

개발 순서

1. okta.com에서 개발자 계정을 만든다. 

2. Okta에서 Open ID Connect 클라이언트 앱을 추가

3. OpenID Connect 를 위한 앱 설정

4. Okta SDK dependencies를 설치

5. Okta Sign In 위젯 통합

6. login/logout 버튼을 위한 login status component 추가

7. routes를 연결할 수 있는 App Module config 수정

 

 

3. 

 

ng generate interface config/MyAppConfig

으로 config 파일을 생성한다. 

 

 

Client Id는 클라이언트 앱의 public identifier 

issuer는 토큰의 발행자이고 Okta Authorization Server에서 승인하는 곳이다.

redirectUri는 유저가 한 번 로그인하면 보내는 곳이다.

Scopes는 유저 정보 접근을 제공한다. 

openid는 인증 요청에 필요한 것

profile은 유저의 성, 이름, 휴대폰번호 등등

email은 유저의 이메일 주소.

 

 

4. 

 

Okta Sign-In Widget, Okta Angular SDK를 사용한다. 

Okta Sign-In Widget은 자바스크립트 라이브러리이다. 

Okta Angular SDK는 authentication과 authorization에 관련한 Angular Router 통합을 제공한다. 

OAuth 2.0 API를 사용한 Okta로부터 login/logout 기능

유저 정보를 갖고오고 authentication 상태를 확정한다. 

 

설치는 다음 명령어를 입력하여 설치한다. 

npm install @okta/okta-signin-widget

npm install @okta/okta-angular

 

5.

 

 

 

6. 

 

login component는 로그인 화면을 구성한다.

ng generate component components/login

 

login.component.ts 의 내용을 다음과 같이 작성

import { Component,Inject, OnInit } from '@angular/core';
import { OktaAuthStateService } from '@okta/okta-angular';
import { OKTA_AUTH } from '@okta/okta-angular';
import { OktaAuth } from '@okta/okta-auth-js';
import * as OktaSignIn from '@okta/okta-signin-widget';

import myAppConfig from '../../config/my-app-config';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {

  oktaSignin: any;

  constructor(private oktaAuthService: OktaAuthStateService,
    @Inject(OKTA_AUTH) private oktaAuth: OktaAuth) {

    this.oktaSignin = new OktaSignIn({
      logo: 'assets/images/logo.png',
      baseUrl: myAppConfig.oidc.issuer.split('/oauth2')[0],
      clientId: myAppConfig.oidc.clientId,
      redirectUri: myAppConfig.oidc.redirectUri,
      authParam:{
        pkce:true,
        issuer: myAppConfig.oidc.issuer,
        scopes: myAppConfig.oidc.scopes
      }
    });
   }
  ngOnInit(): void {
    this.oktaSignin.remove();
    this.oktaSignin.renderEl({
      el:'#okta-sign-in-widget'},
    (response:any) => {
      if(response.status === 'SUCCESS'){
        this.oktaAuth.signInWithRedirect();
      }
    },
    (error:any) => {
      throw error;
    }
  );
  }
}

 

el의 값은 login.component.html 의 div id 값과 같아야 한다. 

주어진 id 값을 받아서 그린다는 뜻이다. 

 

 

login status component는 로그인/로그아웃 버튼을 구성한다. 

ng generate component components/LoginStatus

 

login-status.component.ts의 내용은 다음과 같이 작성한다. 

import { Component,Inject, OnInit } from '@angular/core';
import { OktaAuthStateService } from '@okta/okta-angular';
import { OKTA_AUTH } from '@okta/okta-angular';
import { OktaAuth } from '@okta/okta-auth-js';

@Component({
  selector: 'app-login-status',
  templateUrl: './login-status.component.html',
  styleUrls: ['./login-status.component.css']
})
export class LoginStatusComponent implements OnInit {

  isAuthenticated: boolean = false;
  userFullName: string;

  constructor(private oktaAuthService: OktaAuthStateService,
    @Inject(OKTA_AUTH) private oktaAuth: OktaAuth) { }

  ngOnInit(): void {
    this.oktaAuthService.authState$.subscribe(
      (result) => {
        this.isAuthenticated = result.isAuthenticated;
        this.getUserDetails();
      }
    )
  }

  getUserDetails(){
    if(this.isAuthenticated){

      this.oktaAuth.getUser().then(
        (res)=>{
          this.userFullName = res.name;
        }
      );
    }
  }

  logout(){
    this.oktaAuth.signOut();
  }
}

 

 

 

src 폴더에 있는 전역으로 적용되는 styles.css에서 

.au-btn-submit 을 검색해서 복사한 다음

login-status.component.css 파일에 붙여넣고 

.security-btn으로 이름 변경하고 내용을 수정한다. 

 

styles.css에서 .form-header를 .login-status-header로 변경한다. 

 

styles.css에서 .au-input을 .login-status-user-info로 변경하고

내용은 solid, font-size, color를 삭제한다. 

 

 

 

7. 

 

app.module.ts는 다음과 같이 작성한다. 

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { ProductListComponent } from './components/product-list/product-list.component';
import { HttpClientModule } from '@angular/common/http';
import { ProductService } from './services/product.service';
import { Routes, RouterModule, Router} from '@angular/router';
import { ProductCategoryMenuComponent } from './components/product-category-menu/product-category-menu.component';
import { SearchComponent } from './components/search/search.component';
import { ProductDetailsComponent } from './components/product-details/product-details.component';

import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { CartStatusComponent } from './components/cart-status/cart-status.component';
import { CartDetailsComponent } from './components/cart-details/cart-details.component';
import { CheckoutComponent } from './components/checkout/checkout.component';
import { ReactiveFormsModule } from '@angular/forms';
import { LoginComponent } from './components/login/login.component';
import { LoginStatusComponent } from './components/login-status/login-status.component';

import {
  OKTA_CONFIG,
  OktaAuthModule,
  OktaCallbackComponent,
} from '@okta/okta-angular';

import myAppConfig from './config/my-app-config';

import { OktaAuth } from '@okta/okta-auth-js';

const oktaConfig = Object.assign({
  onAuthRequired:(injector:any)=>{
    const router=injector.get(Router);
    router.navigate(['/login']);
  }
}, myAppConfig.oidc);

const oktaAuth = new OktaAuth(oktaConfig);

const routes: Routes = [
  {path: 'login/callback', component: OktaCallbackComponent},
  {path: 'login', component: LoginComponent},
  {path: 'checkout', component: CheckoutComponent},
  {path: 'cart-details', component: CartDetailsComponent},
  {path: 'products/:id', component: ProductDetailsComponent},
  {path: 'search/:keyword', component: ProductListComponent},
  {path: 'category/:id/:name', component: ProductListComponent},
  {path: 'category', component: ProductListComponent},
  {path: 'products', component: ProductListComponent},
  {path: '', redirectTo:'/products',pathMatch:'full'},
  {path: '**', redirectTo:'/products',pathMatch:'full'}

];
@NgModule({
  declarations: [
    AppComponent,
    ProductListComponent,
    ProductCategoryMenuComponent,
    SearchComponent,
    ProductDetailsComponent,
    CartStatusComponent,
    CartDetailsComponent,
    CheckoutComponent,
    LoginComponent,
    LoginStatusComponent
  ],
  imports: [
    RouterModule.forRoot(routes),
    BrowserModule,
    HttpClientModule,
    NgbModule,
    ReactiveFormsModule,
    OktaAuthModule
  ],
  providers: [ProductService,{provide: OKTA_CONFIG, useValue:{oktaAuth}}],
  bootstrap: [AppComponent]
})
export class AppModule { }

onAuthRequred: 의 내용은

승인이 필요할 경우  Redirect 하는데

Redirect할 때 유저가 로그인 페이지(/login)로 갈 수 있게 설정한다.

 

OktaCallbackComponent는 한번 유저가 인증받으면 redirect를 해야 하는데

보통 response를 받아서 OAuth+OIDC 토큰을 저장해야 하지만

OktaCallbackComponent가 이걸 대신 해준다.