कोणीय रीडायरेक्ट लॉगिन पृष्ठ पर


122

मैं Asp.Net MVC दुनिया से आता हूं जहां उपयोगकर्ता उन पेज तक पहुंचने की कोशिश कर रहे हैं जो वे अधिकृत नहीं हैं, स्वचालित रूप से लॉगिन पृष्ठ पर पुनः निर्देशित कर दिए जाते हैं।

मैं कोणीय पर इस व्यवहार को पुन: पेश करने की कोशिश कर रहा हूं। मैं @CanActivate डेकोरेटर के पास आया था, लेकिन इसका परिणाम यह है कि घटक बिल्कुल नहीं दे रहा है, कोई पुनर्निर्देशन नहीं है।

मेरा प्रश्न निम्नलिखित है:

  • क्या कोणीय इस व्यवहार को प्राप्त करने का एक तरीका प्रदान करता है?
  • यदि हां, तो कैसे? क्या यह एक अच्छा अभ्यास है?
  • यदि नहीं, तो कोणीय में उपयोगकर्ता प्राधिकरण से निपटने के लिए सबसे अच्छा अभ्यास क्या होगा?

मैंने एक वास्तविक निर्देश जोड़ा है जो दिखाता है कि यदि आप ध्यान देना चाहते हैं, तो सामान कैसे करना है।
माइकल ओरीएल

यह उत्तर उपयोगी हो सकता है: stackoverflow.com/a/59008239/7059557
अमीरराजा-फरहलगा

जवाबों:


86

अद्यतन: मैंने गीथब पर OAuth2 एकीकरण के साथ एक पूर्ण कंकाल कोणीय 2 परियोजना प्रकाशित की है जो कार्रवाई में नीचे दिए गए निर्देश को दर्शाता है।

ऐसा करने का एक तरीका ए के उपयोग के माध्यम से होगा directive। कोणीय 2 के विपरीत components, जो मूल रूप से नए HTML टैग (संबद्ध कोड के साथ) हैं जो आप अपने पेज में डालते हैं, एक उत्तरदायी निर्देश एक विशेषता है जिसे आप एक टैग में रखते हैं जिससे कुछ व्यवहार उत्पन्न होता है। यहां डॉक्स

आपके कस्टम विशेषता की उपस्थिति से उस घटक (या 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>

फिर आप उपयोगकर्ता को अपने ऐप में लॉगिन दृश्य में नेविगेट / रीडायरेक्ट करना चाहेंगे, और वहां प्रमाणीकरण को संभालेंगे। आपको वर्तमान मार्ग को उस व्यक्ति को बदलना होगा जिसे आप करना चाहते थे। तो उस स्थिति में आप अपने निर्देश के कार्य में राउटर ऑब्जेक्ट प्राप्त करने के लिए निर्भरता इंजेक्शन का उपयोग करेंगे 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}
])

यदि, इसके बजाय, आपको उपयोगकर्ता को किसी बाहरी URL, जैसे आपका OAuth2 सर्वर, पर पुनर्निर्देशित करने की आवश्यकता है , तो आपको अपना निर्देश निम्न जैसा कुछ करना होगा:

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

4
यह काम करता हैं! धन्यवाद! मुझे यहाँ एक और विधि भी मिली - github.com/auth0/angular2-authentication-sample/blob/master/src/… मैं यह नहीं कह सकता कि कौन सा तरीका बेहतर है, लेकिन शायद कोई इसे उपयोगी भी पाएगा।
सर्गेई

3
धन्यवाद ! मैंने एक नया मार्ग भी जोड़ा है जिसमें एक पैरामीटर / संरक्षित /: रिटर्न यूआरएल, रिटर्न यूआरएल होने का स्थान है।पथ () निर्देश के ngOnInit पर इंटरसेप्ट किया गया है। यह मूल रूप से संकेतित url में लॉगिन करने के बाद उपयोगकर्ता को नेविगेट करने की अनुमति देता है।
अमौरी

1
एक सरल समाधान के लिए नीचे दिए गए उत्तर देखें। कुछ भी इस सामान्य (पुनर्निर्देशित यदि प्रमाणित नहीं है) एक एकल वाक्य जवाब के साथ एक सरल समाधान होना चाहिए।
रिक ओ'शिआ

7
नोट: यह उत्तर Angular 2 के बीटा या रिलीज़-उम्मीदवार संस्करण को संबोधित करता है और अब Angular 2 के फाइनल के लिए लागू नहीं है।
जँबाई

1
वहाँ इस का एक बहुत अच्छा समाधान अब का उपयोग कर कोणीय गार्ड
mwilson

116

यहाँ एक अद्यतन उदाहरण कोणीय 4 का उपयोग कर रहा है (यह भी कोणीय 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 लॉगिन पृष्ठ पर पुनर्निर्देश करता है

लॉग इन पृष्ठ पर क्वेरी params में मूल 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;
    }
}

पूर्ण उदाहरण और कार्यशील डेमो के लिए आप इस पोस्ट को देख सकते हैं


6
मेरे पास एक अनुवर्ती क्यू है, यदि वह अभी भी संरक्षित मार्ग तक पहुंचने में सक्षम होने currentUserमें एक मनमाना मूल्य निर्धारित नहीं localStorageकर रहा है? जैसे। localStorage.setItem('currentUser', 'dddddd')?
jsd

2
यह क्लाइंट-साइड सुरक्षा को बायपास करेगा। लेकिन यह टोकन को भी साफ कर देगा जो कि सर्वर-साइड लेनदेन के लिए आवश्यक होगा, इसलिए एप्लिकेशन से कोई उपयोगी डेटा नहीं निकाला जा सकता है।
मैट मेंग

55

अंतिम राउटर के साथ उपयोग

नए राउटर की शुरुआत के साथ मार्गों की रक्षा करना आसान हो गया। आपको एक गार्ड को परिभाषित करना होगा, जो सेवा के रूप में कार्य करता है, और इसे मार्ग में जोड़ता है।

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जहाँ आपका व्यवसाय तर्क रहता है उपयोगकर्ता में हो या ना किया गया है या नहीं जगह के लिए खड़ा है। आप इसे डीआई के साथ कंस्ट्रक्टर में आसानी से जोड़ सकते हैं।

जब उपयोगकर्ता आपकी वेबसाइट पर एक नए यूआरएल पर नेविगेट करता है, तो सक्रिय विधि को वर्तमान निर्देश के साथ बुलाया जाता है। इसमें से आप url को पकड़ सकते हैं और तय कर सकते हैं कि इसकी अनुमति है या नहीं। यदि लॉगिन पृष्ठ पर सिर्फ रीडायरेक्ट नहीं है।

एक आखिरी चीज यह काम करने के लिए बनी हुई है, इसे एक में निर्मित के बजाय हमारे मुख्य घटक को पास करना है।

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

इस समाधान के साथ इस्तेमाल नहीं किया जा सकता है @CanActive जीवनचक्र सज्जाकार के , क्योंकि यदि यह पास किया गया फ़ंक्शन झूठा हल करता है, तो सक्रिय विधि RouterOutletको नहीं बुलाया जाएगा।

इसके बारे में एक विस्तृत ब्लॉग पोस्ट भी लिखी: https://medium.com/@blacksonic86/authentication-in-angular-2-958052c64492


2
इसके बारे में और अधिक विस्तृत ब्लॉग पोस्ट माध्यम से लिखा ।.com
blacksonic86/…

नमस्कार @Blacksonic। बस ng2 में खुदाई शुरू की। मैंने आपके सुझाव का पालन किया लेकिन इस त्रुटि को gulp-tslint के दौरान प्राप्त किया: Failed to lint <classname>.router-outlet.ts[15,28]. In the constructor of class "LoggedInRouterOutlet", the parameter "nameAttr" uses the @Attribute decorator, which is considered as a bad practice. Please, consider construction of type "@Input() nameAttr: string". इस संदेश से छुटकारा पाने के लिए कंस्ट्रक्टर ("_parentRounter") में क्या बदल सकता है, यह पता नहीं लगा सका। कोई विचार?
leovrf

घोषणा को अंतर्निहित राउटरऑउटलेट में अंतर्निहित अंतर्निहित से कॉपी किया गया है जिसमें विस्तारित वर्ग के समान हस्ताक्षर हैं, मैं इस लाइन के लिए विशिष्ट tslint नियम को अक्षम कर दूंगा
Blacksonic

मुझे mgechev स्टाइल-गाइड पर एक संदर्भ मिला ("पैरामीटर पैरामीटर डेकोरेटर के ऊपर इनपुट पसंद करें")। लाइन को बदल दिया _parentRouter: Router, @Input() nameAttr: string,और tslint अब त्रुटि नहीं उठाता है। इसके अलावा कोणीय कोर से "इनपुट" आयात को "इनपुट" में बदल दिया। उम्मीद है की यह मदद करेगा।
lerrf

1
2.0.0-rc.1 के साथ एक समस्या है क्योंकि राउटरऑउटलेट का निर्यात नहीं किया गया है और इसे विस्तारित करने की कोई संभावना नहीं है
mkuligowski

53

कृपया, राउटर आउटलेट को ओवरराइड न करें! यह नवीनतम राउटर रिलीज (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############


2
अच्छा लगा, @ ब्लैकसनिक का जवाब मेरे लिए पूरी तरह से डिप्रेस्ड राउटर के साथ काम कर रहा था। मुझे नए राउटर में अपग्रेड करने के बाद बहुत रिफ्लेक्टर करना पड़ा। आपका समाधान बस मुझे क्या चाहिए!
and:

मैं अपने app.component में काम करने के लिए canActivate नहीं कर सकते। यदि प्रमाणित नहीं है तो मैं उपयोगकर्ता को पुनर्निर्देशित करना चाहूंगा। यह मेरे पास मौजूद राउटर का संस्करण है (अगर मुझे इसे अपडेट करने की आवश्यकता है तो मैं git bash कमांड लाइन का उपयोग करके कैसे करूं?) संस्करण I: "@ कोणीय / राउटर": "2.0.0-rc.1"
AngularM

क्या मैं अन्य घटक मार्ग की सुरक्षा के लिए एक ही वर्ग (AuthGuard) का उपयोग कर सकता हूं?
त्सिरो

4

ऊपर दिए गए भयानक उत्तरों के बाद मैं भी चाहूंगा CanActivateChild: बाल मार्गों की रखवाली करना। इसका उपयोग guardएसीएल जैसे मामलों के लिए बच्चों के मार्गों को जोड़ने के लिए किया जा सकता है

यह इस प्रकार चलता है

src / app / schem-guard.service.ts (अंश)

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 (अंश)

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 {}

यह https://angular.io/docs/ts/latest/guide/router.html# .# can-actor- guard से लिया गया है


2

इस कोड को देखें

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

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;      
    }
  }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.