【问题标题】:Angular 2 authenticate stateAngular 2 身份验证状态
【发布时间】:2016-08-29 04:04:12
【问题描述】:

我已经使用 Angular 2 实现了一个登录页面。登录后,我从服务器获取 jsonwebtoken、userId、userRole、userName。我将此信息存储在本地存储中,以便我可以随时访问它并在用户刷新页面时保持登录状态。

AuthService.ts

import {Injectable} from "@angular/core";

@Injectable()
export class AuthService {
  redirectUrl: string;

  logout() {
    localStorage.clear();
  }

  isLoggedIn() {
    return localStorage.getItem('token') !== null;
  }

  isAdmin() {
    return localStorage.getItem('role') === 'admin';
  }

  isUser() {
    return localStorage.getItem('role') === 'user';
  }

}

为了检查登录状态,我只是检查本地存储中是否存在令牌。由于 localstorage 是可编辑的,因此只需在 localstorage 中添加任何令牌都会绕过登录页面。同样,如果客户端在本地存储中编辑用户角色,客户端可以轻松访问管理或用户页面。

我该如何解决这些问题?

这更像是一个普遍的问题,我想知道网站是如何保持登录状态的?

附: NodeJS服务器端登录代码生成jsonwebtoken

const jwt = require('jsonwebtoken');
const User = require('../models/User');

/**
 * POST /login
 * Sign in using username and password
 */
exports.postLogin = (req, res, next) => {
    User.findOne({username: req.body.username})
        .then(user=> {
            if (!user) {
                res.status(401);
                throw new Error('Invalid username');
            }
            return user.comparePassword(req.body.password)
                .then(isMatch=> {
                    if (isMatch != true) {
                        res.status(401);
                        throw new Error('Invalid password');
                    }
                    let token = jwt.sign({user: user}, process.env.JWT_SECRET, {
                        expiresIn: process.env.JWT_TIMEOUT
                    });
                    return res.status(200).json({
                        success: true,
                        token: token,
                        userId: user._id,
                        role:user.role,
                        name:user.name
                    });
                });
        })
        .catch(err=>next(err));
};

-谢谢

【问题讨论】:

    标签: javascript node.js authentication angular local-storage


    【解决方案1】:
    1. 令牌应该是唯一的并且难以键入(因为长度很大)。此外,它们应该以某种频率刷新。最好在此阅读oAuth docs

    2. 角色不应存储在客户端。只检查服务器。 此外,在使用 oAuth 时,请考虑使用 Scopes。

    【讨论】:

      【解决方案2】:

      您在服务器端对身份验证令牌进行数字签名:

      jwt.sign({user: user}, process.env.JWT_SECRET, {
          expiresIn: process.env.JWT_TIMEOUT
      })
      

      然后,服务器端应在后续请求中验证此签名。客户端更改token内容时失效。

      【讨论】:

        【解决方案3】:

        将令牌存储在 localStorage/sessionStorage 中,并在需要时使用服务器验证令牌。我有以下实现来验证令牌

        UserProfileService.ts

        @Injectable()
        export class UserProfileService {
          private isLoggedIn: boolean = false;
          private apiEndPoint: string;
          constructor(private http: Http) {
            this.apiEndPoint = environment.apiEndpoint;
          }
        
          login(token: string) {
            localStorage.setItem('auth_token', token);
            this.isLoggedIn = true;
          }
        
          logout(){
            localStorage.removeItem('auth_token');
            this.isLoggedIn = false;
          }
        
          isAuthorized(): Observable<boolean> {
            if (!this.isLoggedIn) {
              let authToken = localStorage.getItem('auth_token');
              if(authToken){
                let headers = new Headers();
                headers.append('Content-Type', 'application/json');
                headers.append('Accept', 'application/json');
                headers.append('Authorization', `Bearer ${authToken}`);
                return this.http.get(`${this.apiEndPoint}/validate-token`, { headers: headers })
                .map(res => {
                  let serverResponse = res.json();
                  this.isLoggedIn = serverResponse['valid'];
                  if (!this.isLoggedIn) {
                    localStorage.removeItem('auth_token');
                  }
                  return this.isLoggedIn;
                })
                .catch(this._serverError);
              }
            }
            return Observable.of(this.isLoggedIn);
          }
        
          private _serverError(err: any) {
            localStorage.removeItem('auth_token');
            if(err instanceof Response) {
              console.log(err.json());
              return Observable.of(false);
            }
            return Observable.of(false);
          }
        
        }
        

        AuthService.ts

        @Injectable()
        export class CanActivateAuthGuard implements CanActivate, CanActivateChild, CanLoad {
          constructor(private userProfileService: UserProfileService, private router: Router) { }
        
          canLoad(route: Route) {
            return this.userProfileService.isAuthorized().map(authorized => {
              if(authorized) {
                return authorized;
              } else {
                let url = `/${route.path}`;
                this.router.navigate(['/login'], { queryParams: { redirectTo: url } });
                return authorized;
              }
            });
          }
        
          canActivate(
            next: ActivatedRouteSnapshot,
            state: RouterStateSnapshot
          ) {
            return this.userProfileService.isAuthorized().map(authorized => {
              if(authorized) {
                return authorized;
              } else {
                this.router.navigate(['/login'], { queryParams: { redirectTo: state.url } });
                return authorized;
              }
            });
          }
        
          canActivateChild(
            route: ActivatedRouteSnapshot,
            state: RouterStateSnapshot
          ) {
            return this.canActivate(route, state);
          }
        }
        

        【讨论】:

          猜你喜欢
          • 2017-11-19
          • 2017-05-09
          • 2017-02-24
          • 1970-01-01
          • 2017-01-22
          • 2011-11-12
          • 1970-01-01
          • 1970-01-01
          • 2016-09-25
          相关资源
          最近更新 更多