【问题标题】:How to avoid logout after a refresh in Angular如何避免在 Angular 中刷新后注销
【发布时间】:2023-01-26 12:02:45
【问题描述】:

我在刷新页面后注销时遇到问题。我认为问题出在获取当前用户的方法或检查用户管理员的方法中。

admin-auth-guard.service.ts

export class AdminAuthGuardService implements CanActivate {

constructor(
    private router: Router,
    private userService: UserService,
) { }

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
    return this.checkLogin();
}

checkLogin(): Observable<boolean> {
    return this.userService.getCurrentUser().pipe(
        map(user => {
            if (user) {
                const isUserAdmin = this.userService.isRoleAdmin();
                if (isUserAdmin) {
                    return true;
                } else {
                    this.router.navigate(['/forbidden']);
                    return false;
                    
                }
            } else {
                this.router.navigate(['/login']);
                return false;
            }
        })
    );
}

}

用户服务.ts

导出类用户服务{
    
      当前用户!:用户 |无效的;
    
      private usersUrl = `${SERVER_API_URL}/api/user`;
      私人 apiServerUrl = environment.apiBaseUrl;
    
      构造函数(私有 http: HttpClient){ }
    
      getCurrentUser(): 可观察的 {
        返回 this.http.get(`${this.usersUrl}/current-user`);
      }
    
      isRoleAdmin(): 布尔值 {
        如果(this.currentUser){
          返回 this.currentUser.authorities.some((authority: string) => authority === Authority.ADMIN);
        } 别的 {
          返回假;
        }
      }
    
      isRoleUser(): 布尔值 {
        如果(this.currentUser){
          返回 this.currentUser.authorities.some((authority: string) => authority === Authority.USER);
        } 别的 {
          返回假;
        }
      }
    
      isRoleDeleter(): 布尔值 {
        如果(this.currentUser){
          返回 this.currentUser.authorities.some((authority: string) => authority === Authority.DELETER);
        } 别的 {
          返回假;
        }
      }
    
      getStudentsData(userId: number): 可观察{
        返回 this.http.get(`${this.apiServerUrl}/api/user/edit/${userId}`);
      }
    
      updateUser(profesor: Profesors[], userId: number): Observable{
        return this.http.put(`${this.apiServerUrl}/api/user/update/${userId}`, 教授);
      }
    
    }

登录组件.ts

导出类 LoginComponent 实现 OnInit {
    
      验证=假; // 显示加载
      登录失败=假; // 显示登录失败信息
    
      用户凭据!:用户凭据;
      private loggedIn = new BehaviorSubject(localStorage.getItem("isLoggedIn") === "true");
    
    
      构造函数(
        私人登录服务:登录服务,
        私人路由器:路由器,
        私有用户服务:UserService
      ) {
      }
    
      ngOnInit(): void {
        this.userCredentials = new UserCredentials();
    
      }
    
    
      登录() {
        this.authenticating = true;
        this.loginFailed = false;
    
        this.loginService.authenticate(this.userCredentials).subscribe(
          (jwtToken: JwtToken) => this.successfulLogin(jwtToken),
          () => this.loginFailed = true
        ).add(() => this.authenticating = false);
      }
    
      成功登录(jwtToken:JwtToken){
        localStorage.setItem('token', jwtToken.token); // 将令牌值存储到本地存储
        this.userService.getCurrentUser().subscribe((currentUser: User) => this.userService.currentUser = currentUser);
        this.router.navigate(['/home']);
      }
      isUserLoggedIn(): 布尔值 {
        返回!this.userService.currentUser;
      }
    }

用户.model.ts

出口类用户{
        身份证号;
        用户名:字符串;
        名字:字符串;
        姓氏:字符串;
        权限:字符串[];
    
        构造函数(id: number, username: string, firstName: string, lastName: string, authorities: string[]){
            这个.id = id;
            this.username = 用户名;
            this.firstName = firstName;
            this.lastName = lastName;
            this.authorities = 权威;
        }
    }

【问题讨论】:

  • 根据您获取当前用户的方式,如果用户未连接,它可能会返回 403。结果,Observable 将失败。你能检查开发工具中的网络选项卡吗?
  • 当前用户在网络中返回 200
  • 您还可以在此处包括 User 类型吗?它是一个接口,还是一个类?我的想法是确保User 是一个类,并在那里实现isRoleAdminisRoleUserisRoleDeleter。这样你也可以删除功能羡慕代码味道也是如此。然后,您将能够在您已有的 user 实例上调用这些方法,而不是依赖 UserService 为您执行此操作。当您检查角色时,很可能 UserService.currentUser 未初始化。
  • 用户是具有构造函数的类
  • 你在代码中的任何地方调用这个构造函数吗?我没有看到这个构造函数的任何用法

标签: angular authentication angular-material typescript2.0


【解决方案1】:

我将从一些重构开始:

User类中移动角色检查方法:

export class User {
  id: number;
  username: string;
  firstName: string;
  lastName: string;
  authorities: string[];

  constructor(user?: Partial<User>) {
    Object.assign(this, user);
  }

  isRoleAdmin = () => {
      return this.authorities.some(authority => authority === Authority.ADMIN);
  }

  isRoleUser = () {
    return this.authorities.some(authority => authority === Authority.USER);
  }

  isRoleDeleter = () {
    return this.authorities.some(authority => authority === Authority.DELETER);
  }
}

然后你可以从服务中删除角色方法,并确保调用 User 类构造函数,否则它将不是 User 类的实例,它只是一个普通对象:

export class UserService {
  currentUser!: User | null;

  private usersUrl = `${SERVER_API_URL}/api/user`;
  private apiServerUrl = environment.apiBaseUrl;

  constructor(private http: HttpClient) {}

  getCurrentUser(): Observable<User> {
    return this.http.get<User>(`${this.usersUrl}/current-user`).pipe(
        map(user => new User(user))
    );
  }

  getStudentsData(userId: number): Observable {
    return this.http.get(`${this.apiServerUrl}/api/user/edit/${userId}`);
  }

  updateUser(profesor: Profesors[], userId: number): Observable {
    return this.http.put(
      `${this.apiServerUrl}/api/user/update/${userId}`,
      profesor
    );
  }
}

然后,守卫可以这样实现:

export class AdminAuthGuardService implements CanActivate {
  constructor(private router: Router, private userService: UserService) {}

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean> {
    return this.checkLogin();
  }

  checkLogin(): Observable<boolean> {
    return this.userService.getCurrentUser().pipe(
      map((user) => {
        if (!user) {
          this.router.navigate(["/login"]);
          return false;
        }
        const isAllowed = user.isRoleAdmin();
        if (!isAllowed) {
          this.router.navigate(["/forbidden"]);
        }
        return isAllowed;
      })
    );
  }
}

【讨论】:

  • 我收到此错误:错误 NullInjectorError:R3InjectorError(AppModule)[用户 -> 用户 -> 用户]:NullInjectorError:没有用户提供者!
  • 你试图在哪里注入用户?您应该注入 UserService,而不是 User
  • 好的,我解决了这个问题,但现在我又遇到了另一个错误:错误错误:未捕获(承诺):TypeError:user.isRoleAdmin 不是函数 TypeError:user.isRoleAdmin 不是函数
  • 然后按照此响应中的说明尝试更改 User 类(第一个代码 sn-p)。确保还包括我在 UserService 中所做的更改,因为存在重要的用户映射,将从后端接收的普通 json 对象转换为实际的 User 实例。
【解决方案2】:

我通常做的一件事是将 ID 保存在 localStorage 上。

当用户登录时,它会将 id 保存在 localStorage 中,当您尝试从该用户那里获取任何内容时,只需将 id 保存到 localStorage 中即可。如果您想注销,只需从那里删除id,一切正常!

我从来没有遇到过这个问题,它总是对我有用!

笔记:我只在测试某些东西时使用这种方式,而不是在它应该是活的时候

【讨论】:

    【解决方案3】:

    如果您明确说明问题所在或至少准确描述您所看到的情况,将会很有帮助。无论如何,由于我不确定,这里有一些可能的解决方案:

    问题1

      isUserLoggedIn(): boolean {
        return !this.userService.currentUser;
      }
    

    这个逻辑是倒退的。您通过查看 this.userService.currentUser 是否未定义来检查用户是否已登录。它需要检查它是否已定义。

    return !!this.userService.currentUser;
    

    问题2我也看不到您在哪里设置 currentUser。因此,所有检查都将失败。

    问题3用 null 检查一个对象是没有意义的。空用户将返回 true。相反,像这样声明 currentUser :

    currentUser?: User;
    

    【讨论】:

      猜你喜欢
      • 2019-04-04
      • 1970-01-01
      • 2014-04-01
      • 2020-01-02
      • 1970-01-01
      • 1970-01-01
      • 2016-05-09
      • 2018-10-20
      • 1970-01-01
      相关资源
      最近更新 更多