program story

로그인 페이지로의 각도 재 지정

inputbox 2020. 7. 26. 13:01
반응형

로그인 페이지로의 각도 재 지정


권한이없는 페이지에 액세스하려는 사용자가 자동으로 로그인 페이지로 리디렉션되는 Asp.Net MVC 세계에서 왔습니다.

Angular 에서이 동작을 재현하려고합니다. @CanActivate 데코레이터에 도달했지만 구성 요소가 전혀 렌더링되지 않고 리디렉션되지 않습니다.

내 질문은 다음과 같습니다

  • Angular는이 동작을 수행 할 수있는 방법을 제공합니까?
  • 그렇다면 어떻게? 좋은 습관입니까?
  • 그렇지 않은 경우 Angular에서 사용자 권한을 처리하는 가장 좋은 방법은 무엇입니까?

업데이트 : 아래에 언급 된 지침을 보여주는 Github에 OAuth2 통합 이 포함 된 전체 골격 Angular 2 프로젝트를 게시했습니다 .

이를 수행하는 한 가지 방법은을 사용하는 것 directive입니다. components페이지에 삽입하는 기본적으로 새로운 HTML 태그 (관련 코드가있는) 인 Angular 2와 달리 속성 지시문은 태그에 삽입하여 일부 동작이 발생하는 속성입니다. 여기에 문서가 있습니다 .

사용자 지정 특성이 있으면 지시문을 배치 한 구성 요소 (또는 HTML 요소)에 문제가 발생합니다. 현재 Angular2 / OAuth2 응용 프로그램에 사용하는이 지시문을 고려하십시오.

import {Directive, OnDestroy} from 'angular2/core';
import {AuthService} from '../services/auth.service';
import {ROUTER_DIRECTIVES, Router, Location} from "angular2/router";

@Directive({
    selector: '[protected]'
})
export class ProtectedDirective implements OnDestroy {
    private sub:any = null;

    constructor(private authService:AuthService, private router:Router, private location:Location) {
        if (!authService.isAuthenticated()) {
            this.location.replaceState('/'); // clears browser history so they can't navigate with back button
            this.router.navigate(['PublicPage']);
        }

        this.sub = this.authService.subscribe((val) => {
            if (!val.authenticated) {
                this.location.replaceState('/'); // clears browser history so they can't navigate with back button
                this.router.navigate(['LoggedoutPage']); // tells them they've been logged out (somehow)
            }
        });
    }

    ngOnDestroy() {
        if (this.sub != null) {
            this.sub.unsubscribe();
        }
    }
}

이것은 내가 작성한 인증 서비스를 사용하여 사용자가 이미 로그인했는지 여부를 결정 하고 인증 이벤트에 가입 하여 사용자가 로그 아웃하거나 시간 초과되면 사용자를 쫓아 낼 수 있습니다.

같은 일을 할 수 있습니다. 필요한 쿠키 또는 사용자가 인증되었음을 나타내는 기타 상태 정보가 있는지 확인하는 지시문을 작성합니다. 원하는 플래그가없는 경우 사용자를 기본 공개 페이지 (나처럼) 또는 OAuth2 서버 (또는 기타)로 리디렉션하십시오. 보호해야하는 모든 구성 요소에 해당 지시문 속성을 넣습니다. 이 경우 protected위에 붙여 넣은 지시문에서와 같이 호출 될 수 있습니다 .

<members-only-info [protected]></members-only-info>

그런 다음 사용자를 앱 내 로그인보기로 이동 / 리디렉션하고 인증을 처리하려고합니다. 현재 경로를 원하는 경로로 변경해야합니다. 따라서이 경우 종속성 주입을 사용 하여 지시문 함수 에서 Router 객체 를 얻은 constructor()다음 navigate()메소드를 사용 하여 사용자를 로그인 페이지로 보냅니다 (위의 예와 같이).

이것은 <router-outlet>다음과 같은 태그를 제어하는 일련의 경로가 있다고 가정합니다 .

@RouteConfig([
    {path: '/loggedout', name: 'LoggedoutPage', component: LoggedoutPageComponent, useAsDefault: true},
    {path: '/public', name: 'PublicPage', component: PublicPageComponent},
    {path: '/protected', name: 'ProtectedPage', component: ProtectedPageComponent}
])

대신 OAuth2 서버와 같은 외부 URL로 사용자를 리디렉션 해야하는 경우 지시문에서 다음과 같은 작업을 수행해야합니다.

window.location.href="https://myserver.com/oauth2/authorize?redirect_uri=http://myAppServer.com/myAngular2App/callback&response_type=code&client_id=clientId&scope=my_scope

다음은 Angular 4를 사용하여 업데이트 된 예제 입니다 (Angular 5-8과 호환 가능)

AuthGuard로 보호되는 집 경로가있는 경로

import { Routes, RouterModule } from '@angular/router';

import { LoginComponent } from './login/index';
import { HomeComponent } from './home/index';
import { AuthGuard } from './_guards/index';

const appRoutes: Routes = [
    { path: 'login', component: LoginComponent },

    // home route protected by auth guard
    { path: '', component: HomeComponent, canActivate: [AuthGuard] },

    // otherwise redirect to home
    { path: '**', redirectTo: '' }
];

export const routing = RouterModule.forRoot(appRoutes);

사용자가 로그인하지 않은 경우 AuthGuard가 로그인 페이지로 리디렉션

쿼리 매개 변수의 원래 URL을 로그인 페이지로 전달하도록 업데이트되었습니다.

import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';

@Injectable()
export class AuthGuard implements CanActivate {

    constructor(private router: Router) { }

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
        if (localStorage.getItem('currentUser')) {
            // logged in so return true
            return true;
        }

        // not logged in so redirect to login page with the return url
        this.router.navigate(['/login'], { queryParams: { returnUrl: state.url }});
        return false;
    }
}

전체 예제와 실제 데모를 보려면 이 게시물을 확인하십시오.


최종 라우터와 함께 사용

새로운 라우터가 도입되면서 경로를 보호하는 것이 쉬워졌습니다. 서비스 역할을하는 가드를 정의하고 경로에 추가해야합니다.

import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
import { UserService } from '../../auth';

@Injectable()
export class LoggedInGuard implements CanActivate {
  constructor(user: UserService) {
    this._user = user;
  }

  canActivate() {
    return this._user.isLoggedIn();
  }
}

이제 LoggedInGuard경로를 경로로 전달 providers하고 모듈 배열에 추가하십시오 .

import { LoginComponent } from './components/login.component';
import { HomeComponent } from './components/home.component';
import { LoggedInGuard } from './guards/loggedin.guard';

const routes = [
    { path: '', component: HomeComponent, canActivate: [LoggedInGuard] },
    { path: 'login', component: LoginComponent },
];

모듈 선언 :

@NgModule({
  declarations: [AppComponent, HomeComponent, LoginComponent]
  imports: [HttpModule, BrowserModule, RouterModule.forRoot(routes)],
  providers: [UserService, LoggedInGuard],
  bootstrap: [AppComponent]
})
class AppModule {}

최종 릴리스와 함께 작동하는 방법에 대한 자세한 블로그 게시물 : https://medium.com/@blacksonic86/angular-2-authentication-revisited-611bf7373bf9

더 이상 사용되지 않는 라우터와 함께 사용

보다 강력한 솔루션은 RouterOutlet사용자가 로그인 한 경우 경로 확인을 활성화 할 때 및 경로 확인 을 확장하는 것 입니다. 이렇게하면 모든 구성 요소에 지시문을 복사하여 붙여 넣을 필요가 없습니다. 또한 하위 구성 요소를 기반으로하는 리디렉션이 잘못 될 수 있습니다.

@Directive({
  selector: 'router-outlet'
})
export class LoggedInRouterOutlet extends RouterOutlet {
  publicRoutes: Array;
  private parentRouter: Router;
  private userService: UserService;

  constructor(
    _elementRef: ElementRef, _loader: DynamicComponentLoader,
    _parentRouter: Router, @Attribute('name') nameAttr: string,
    userService: UserService
  ) {
    super(_elementRef, _loader, _parentRouter, nameAttr);

    this.parentRouter = _parentRouter;
    this.userService = userService;
    this.publicRoutes = [
      '', 'login', 'signup'
    ];
  }

  activate(instruction: ComponentInstruction) {
    if (this._canActivate(instruction.urlPath)) {
      return super.activate(instruction);
    }

    this.parentRouter.navigate(['Login']);
  }

  _canActivate(url) {
    return this.publicRoutes.indexOf(url) !== -1 || this.userService.isLoggedIn()
  }
}

UserService비즈니스 로직은 사용자 로그인 여부 상주하는 곳을 의미합니다. 생성자에서 DI를 사용하여 쉽게 추가 할 수 있습니다.

사용자가 웹 사이트에서 새 URL을 탐색하면 현재 명령어와 함께 activate 메소드가 호출됩니다. 그것으로부터 당신은 URL을 잡고 허용 여부를 결정할 수 있습니다. 로그인 페이지로 리디렉션하지 않는 경우

마지막으로 작동하게하려면 내장 된 구성 요소 대신 기본 구성 요소로 전달해야합니다.

@Component({
  selector: 'app',
  directives: [LoggedInRouterOutlet],
  template: template
})
@RouteConfig(...)
export class AppComponent { }

이 솔루션은 @CanActive라이프 사이클 데코레이터 와 함께 사용할 수 없습니다 . 함수가 전달 된 함수가 false를 해결하면의 activate 메소드 RouterOutlet가 호출되지 않기 때문입니다.

https://medium.com/@blacksonic86/authentication-in-angular-2-958052c64492에 대한 자세한 블로그 게시물도 작성했습니다.


라우터 콘센트를 무시하지 마십시오! 최신 라우터 릴리스 (3.0 베타)의 악몽입니다.

대신 CanActivate 및 CanDeactivate 인터페이스를 사용하고 경로 정의에서 클래스를 canActivate / canDeactivate로 설정하십시오.

그렇게 :

{ path: '', component: Component, canActivate: [AuthGuard] },

수업:

@Injectable()
export class AuthGuard implements CanActivate {

    constructor(protected router: Router, protected authService: AuthService)
    {

    }

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean {

        if (state.url !== '/login' && !this.authService.isAuthenticated()) {
            this.router.navigate(['/login']);
            return false;
        }

        return true;
    }
}

참조 : https://angular.io/docs/ts/latest/guide/router.html#!#can-activate-guard


Following the awesome answers above I would also like to CanActivateChild: guarding child routes. It can be used to add guard to children routes helpful for cases like ACLs

It goes like this

src/app/auth-guard.service.ts (excerpt)

import { Injectable }       from '@angular/core';
import {
  CanActivate, Router,
  ActivatedRouteSnapshot,
  RouterStateSnapshot,
  CanActivateChild
}                           from '@angular/router';
import { AuthService }      from './auth.service';

@Injectable()
export class AuthGuard implements CanActivate, CanActivateChild {
  constructor(private authService: AuthService, private router:     Router) {}

  canActivate(route: ActivatedRouteSnapshot, state:    RouterStateSnapshot): boolean {
    let url: string = state.url;
    return this.checkLogin(url);
  }

  canActivateChild(route: ActivatedRouteSnapshot, state:  RouterStateSnapshot): boolean {
    return this.canActivate(route, state);
  }

/* . . . */
}

src/app/admin/admin-routing.module.ts (excerpt)

const adminRoutes: Routes = [
  {
    path: 'admin',
    component: AdminComponent,
    canActivate: [AuthGuard],
    children: [
      {
        path: '',
        canActivateChild: [AuthGuard],
        children: [
          { path: 'crises', component: ManageCrisesComponent },
          { path: 'heroes', component: ManageHeroesComponent },
          { path: '', component: AdminDashboardComponent }
        ]
      }
    ]
  }
];

@NgModule({
  imports: [
    RouterModule.forChild(adminRoutes)
  ],
  exports: [
    RouterModule
  ]
})
export class AdminRoutingModule {}

This is taken from https://angular.io/docs/ts/latest/guide/router.html#!#can-activate-guard


Refer this code, auth.ts file

import { CanActivate } from '@angular/router';
import { Injectable } from '@angular/core';
import {  } from 'angular-2-local-storage';
import { Router } from '@angular/router';

@Injectable()
export class AuthGuard implements CanActivate {
constructor(public localStorageService:LocalStorageService, private router: Router){}
canActivate() {
// Imaginary method that is supposed to validate an auth token
// and return a boolean
var logInStatus         =   this.localStorageService.get('logInStatus');
if(logInStatus == 1){
    console.log('****** log in status 1*****')
    return true;
}else{
    console.log('****** log in status not 1 *****')
    this.router.navigate(['/']);
    return false;
}


}

}
// *****And the app.routes.ts file is as follow ******//
      import {  Routes  } from '@angular/router';
      import {  HomePageComponent   } from './home-page/home- page.component';
      import {  WatchComponent  } from './watch/watch.component';
      import {  TeachersPageComponent   } from './teachers-page/teachers-page.component';
      import {  UserDashboardComponent  } from './user-dashboard/user- dashboard.component';
      import {  FormOneComponent    } from './form-one/form-one.component';
      import {  FormTwoComponent    } from './form-two/form-two.component';
      import {  AuthGuard   } from './authguard';
      import {  LoginDetailsComponent } from './login-details/login-details.component';
      import {  TransactionResolver } from './trans.resolver'
      export const routes:Routes    =   [
    { path:'',              component:HomePageComponent                                                 },
    { path:'watch',         component:WatchComponent                                                },
    { path:'teachers',      component:TeachersPageComponent                                         },
    { path:'dashboard',     component:UserDashboardComponent,       canActivate: [AuthGuard],   resolve: { dashboardData:TransactionResolver } },
    { path:'formone',       component:FormOneComponent,                 canActivate: [AuthGuard],   resolve: { dashboardData:TransactionResolver } },
    { path:'formtwo',       component:FormTwoComponent,                 canActivate: [AuthGuard],   resolve: { dashboardData:TransactionResolver } },
    { path:'login-details', component:LoginDetailsComponent,            canActivate: [AuthGuard]    },

]; 

1. Create a guard as seen below. 2. Install ngx-cookie-service to get cookies returned by external SSO. 3. Create ssoPath in environment.ts (SSO Login redirection). 4. Get the state.url and use encodeURIComponent.

import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from 
  '@angular/router';
import { CookieService } from 'ngx-cookie-service';
import { environment } from '../../../environments/environment.prod';

@Injectable()
export class AuthGuardService implements CanActivate {
  private returnUrl: string;
  constructor(private _router: Router, private cookie: CookieService) {}

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    if (this.cookie.get('MasterSignOn')) {
      return true;
    } else {
      let uri = window.location.origin + '/#' + state.url;
      this.returnUrl = encodeURIComponent(uri);      
      window.location.href = environment.ssoPath +  this.returnUrl ;   
      return false;      
    }
  }
}

참고URL : https://stackoverflow.com/questions/34331478/angular-redirect-to-login-page

반응형