繁体   English   中英

从 .net 核心获取 angular 内的 AD 用户信息的问题

[英]Problem with getting AD user info inside angular from .net core

我的应用程序由两个独立的项目组成:一个.NET 核心后端和一个Angular前端。

我已成功添加 windows AD 身份验证,并且我在我的 Angular 应用程序中获取用户信息,但仅在刷新页面后。

在第一页打开时,我的用户是 null

ERROR TypeError: Cannot read property 'name' of null

刷新后,我可以获取用户信息。 实际发生了什么,我该如何解决这个问题?

public Task < AdUser > GetAdUser(Guid guid) {
  return Task.Run(() => {
    try {
      PrincipalContext context = new PrincipalContext(ContextType.Domain);
      UserPrincipal principal = new UserPrincipal(context);

      if (context != null) {
        principal = UserPrincipal.FindByIdentity(context, IdentityType.Guid,
          guid.ToString());
      }

      return AdUser.CastToAdUser(principal);
    } catch (Exception ex) {
      throw new Exception("Error retrieving AD User", ex);
    }
  });
}

身份服务.ts

getCurrentUser() {
    return this.http.get(this.apiUrl + '/identity/GetAdUser', { withCredentials: true });
}

app.component.rs

this.identityService.getCurrentUser()
.subscribe(res => {
localStorage.setItem('user', JSON.stringify(res));
});

顶部导航.component.ts

user = JSON.parse(localStorage.getItem('user'));

最后,我在顶部导航组件中获取用户数据,因为我需要在其中显示名字和姓氏。

编辑:添加了新代码

应用程序路由.module.ts

    const appRoutes: Routes = [
   {
    path: 'home',
    component: HomeComponent,
    data: { title: 'Home' },
    canActivate: [AuthGuardService]
  },
  {
    path: 'history',
    component: HistoryComponent,
    data: { title: 'History' }
  },
  {
    path: '404',
    component: NotFoundErrorComponent,
    data: { title: 'Error 404' }
  },
  {
    path: '',
    component: HomeComponent,
    pathMatch: 'full'
  },
  {
    path: '**',
    redirectTo: '/404',
    pathMatch: 'full',
    data: { title: 'Error 404' }
  }
];

@NgModule({
  imports: [RouterModule.forRoot(appRoutes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

app.component.ts

    @Component({
     selector: 'app-root',
     templateUrl: './app.component.html',
     styleUrls: ['./app.component.scss']
    })
    export class AppComponent implements OnInit {
     title = 'Home';

    constructor(private titleService: Title,
              private router: Router,
              private activatedRoute: ActivatedRoute { }

    ngOnInit() {
    this.router.events.pipe(
      filter(event => event instanceof NavigationEnd),
      map(() => this.activatedRoute),
      map((route) => {
        while (route.firstChild) { route = route.firstChild; }
        return route;
      }),
      filter((route) => route.outlet === 'primary'),
      mergeMap((route) => route.data))
      .subscribe((event) => this.titleService.setTitle(event.title));
     }
     }

顶部导航.component.ts

    export class TopNavigationComponent implements OnInit {
      constructor(private router: Router) { }

      user;

      ngOnInit() {
       this.user = JSON.parse(localStorage.getItem('user'));
      }
     }

编辑:最终解决方案

应用程序路由.module.ts

const appRoutes: Routes = [
{
path: '',
component: TopNavComponent,
resolve: { userData: IdentityResolverService },
children: [
  {
    path: 'home',
    component: HomeComponent,
    data: { title: 'Home' },
    canActivate: [AuthGuardService]
  },
  {
    path: 'history',
    component: HistoryComponent,
    data: { title: 'History' },
    canActivate: [AuthGuardService]
  },
  {
    path: '404',
    component: NotFoundErrorComponent,
    data: { title: 'Error 404' },
    canActivate: [AuthGuardService]
  },
  {
    path: '',
    redirectTo: 'home',
    pathMatch: 'full',
    canActivate: [AuthGuardService]
  },
  {
    path: '**',
    redirectTo: '/404',
    pathMatch: 'full',
    data: { title: 'Error 404' },
    canActivate: [AuthGuardService]
  }
]
};
]

好的,我将尝试解释这一切是如何工作的。 您的问题是组件中的getCurrentUser在 localStorage 尝试获取数据后执行。

如果您的AppComponent是您的应用程序广告的根组件,则顶部导航组件在应用程序组件 html 中声明,那么您需要确保在 AppComponent 启动之前数据就在那里。

所以,会发生什么(可能的时间线,因为 javascript 的异步性质意味着有时某些步骤将以不同的顺序执行):

  1. 应用程序被路由到您的核心路由
  2. AppComponent 的构造函数执行
  3. TopNavigationComponent 的构造函数执行
  4. getCurrentUser() http 调用开始
  5. TopNavigationComponent 尝试从 localStorage 获取值(出于安全原因,最好使用 SessionStorage)并失败
  6. getCurrentUser() http 调用结束,AppComponent 设置 localStorage 值
  7. 你刷新。 当您到达第 5 步时,已从第 6 步设置本地存储。

最好的解决方案是使用警卫。 如果您需要使用 ADUser 作为安全功能,这对您的情况更有效。 如果防护失败,那么您将不会转换到 AppComponent。

声明一个Guard ,如果数据在那里,然后继续到应用程序组件,Guard 将确保您在本地存储(或 session 存储)中有 ADUser 数据。

解析器(另一种可能的解决方案)将始终在 AppComponent 加载之前运行并且不会阻塞,从而确保在应用程序响应时您拥有数据。

更多关于守卫和解析器的信息在这里

看看下面的守卫:

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(
    private adUserService: ADUserService, 
    private router: Router
  ) {}

  canActivate(next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> {
    // We will return a true if the user is logged in
    // or false otherwise
    return this.adUserService.login().pipe(
      map((x) => {
        // Since my service returned succesfully I will set the
        // locale storage with the appropriate data
        localStorage.setItem('user', JSON.stringify(x));
        // I will also return true to let the router module
        // know that it can proceed
        return true;
      }),
      catchError(() => {
        // If there was an error, I will return false, so the
        // router module will not allow the transition
        // if I want to, I can add the router module to transition
        // to a login page
        return of(false)
      })
    );
  }
}

您可以在此处查看完整的解决方案: stackblitz 示例

要查看实际的语言环境存储,请尝试https://so-angular-route-guards-locale-storage.stackblitz.io/user url。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM