如何在角度4中将observable <user>转换为Obserable <boolean>

时间:2018-07-19 07:02:53

标签: javascript node.js angular typescript rxjs

我想实现canActivate()方法,以便限制管理路由。我将在checkAdmin方法中返回用户类型的observable(在我的服务文件中),但是canActivate方法的返回类型是boolean类型。 因此,我无法将类型为“用户”的observable转换为boolean的observable。请为我提供帮助,因为我是新的有角度和均值堆栈

用户架构模型

/* ===================
   Import Node Modules
=================== */
const mongoose = require('mongoose'); // Node Tool for MongoDB
mongoose.Promise = global.Promise; // Configure Mongoose Promises
const Schema = mongoose.Schema; // Import Schema from Mongoose
const bcrypt = require('bcrypt-nodejs'); // A native JS bcrypt library for NodeJS

// Validate Function to check e-mail length
let emailLengthChecker = (email) => {
  // Check if e-mail exists
  if (!email) {
    return false; // Return error
  } else {
    // Check the length of e-mail string
    if (email.length < 5 || email.length > 30) {
      return false; // Return error if not within proper length
    } else {
      return true; // Return as valid e-mail
    }
  }
};

// Validate Function to check if valid e-mail format
let validEmailChecker = (email) => {
  // Check if e-mail exists
  if (!email) {
    return false; // Return error
  } else {
    // Regular expression to test for a valid e-mail
    const regExp = new RegExp(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
    return regExp.test(email); // Return regular expression test results (true or false)
  }
};

// Array of Email Validators
const emailValidators = [
  // First Email Validator
  {
    validator: emailLengthChecker,
    message: 'E-mail must be at least 5 characters but no more than 30'
  },
  // Second Email Validator
  {
    validator: validEmailChecker,
    message: 'Must be a valid e-mail'
  }
];

// Validate Function to check username length
let usernameLengthChecker = (username) => {
  // Check if username exists
  if (!username) {
    return false; // Return error
  } else {
    // Check length of username string
    if (username.length < 3 || username.length > 15) {
      return false; // Return error if does not meet length requirement
    } else {
      return true; // Return as valid username
    }
  }
};

// Validate Function to check if valid username format
let validUsername = (username) => {
  // Check if username exists
  if (!username) {
    return false; // Return error
  } else {
    // Regular expression to test if username format is valid
    const regExp = new RegExp(/^[a-zA-Z0-9]+$/);
    return regExp.test(username); // Return regular expression test result (true or false)
  }
};

// Array of Username validators
const usernameValidators = [
  // First Username validator
  {
    validator: usernameLengthChecker,
    message: 'Username must be at least 3 characters but no more than 15'
  },
  // Second username validator
  {
    validator: validUsername,
    message: 'Username must not have any special characters'
  }
];

// Validate Function to check password length
let passwordLengthChecker = (password) => {
  // Check if password exists
  if (!password) {
    return false; // Return error
  } else {
    // Check password length
    if (password.length < 8 || password.length > 35) {
      return false; // Return error if passord length requirement is not met
    } else {
      return true; // Return password as valid
    }
  }
};

// Validate Function to check if valid password format
let validPassword = (password) => {
  // Check if password exists
  if (!password) {
    return false; // Return error
  } else {
    // Regular Expression to test if password is valid format
    const regExp = new RegExp(/^(?=.*?[a-z])(?=.*?[A-Z])(?=.*?[\d])(?=.*?[\W]).{8,35}$/);
    return regExp.test(password); // Return regular expression test result (true or false)
  }
};

// Array of Password validators
const passwordValidators = [
  // First password validator
  {
    validator: passwordLengthChecker,
    message: 'Password must be at least 8 characters but no more than 35'
  },
  // Second password validator
  {
    validator: validPassword,
    message: 'Must have at least one uppercase, lowercase, special character, and number'
  }
];

// User Model Definition
const userSchema = new Schema({
  email: { type: String, required: true, unique: true, lowercase: true, validate: emailValidators },
  username: { type: String, required: true, unique: true, lowercase: true, validate: usernameValidators },
  password: { type: String, required: true, validate: passwordValidators },
  isAdmin: { type: Boolean, default: false }
});

// Schema Middleware to Encrypt Password
userSchema.pre('save', function(next) {
  // Ensure password is new or modified before applying encryption
  if (!this.isModified('password'))
    return next();

  // Apply encryption
  bcrypt.hash(this.password, null, null, (err, hash) => {
    if (err) return next(err); // Ensure no errors
    this.password = hash; // Apply encryption to password
    next(); // Exit middleware
  });
});

// Methods to compare password to encrypted password upon login
userSchema.methods.comparePassword = function(password) {
  return bcrypt.compareSync(password, this.password); // Return comparison of login password to password in database (true or false)
};

// Export Module/Schema
module.exports = mongoose.model('User', userSchema);

包含/ profile路由以从mongodb数据库获取用户的http路由

const User = require('../models/user'); // Import User Model Schema

const jwt = require('jsonwebtoken');
const config = require('../config/database');

module.exports = (router) => {
  /* ==============
     Register Route
  ============== */
  router.post('/register', (req, res) => {
    // Check if email was provided
    if (!req.body.email) {
      res.json({ success: false, message: 'You must provide an e-mail' }); // Return error
    } else {
      // Check if username was provided
      if (!req.body.username) {
        res.json({ success: false, message: 'You must provide a username' }); // Return error
      } else {
        // Check if password was provided
        if (!req.body.password) {
          res.json({ success: false, message: 'You must provide a password' }); // Return error
        } else {
          // Create new user object and apply user input
          let user = new User({
            email: req.body.email.toLowerCase(),
            username: req.body.username.toLowerCase(),
            password: req.body.password
          });
          // Save user to database
          user.save((err) => {
            // Check if error occured
            if (err) {
              // Check if error is an error indicating duplicate account
              if (err.code === 11000) {
                res.json({ success: false, message: 'Username or e-mail already exists' }); // Return error
              } else {
                // Check if error is a validation rror
                if (err.errors) {
                  // Check if validation error is in the email field
                  if (err.errors.email) {
                    res.json({ success: false, message: err.errors.email.message }); // Return error
                  } else {
                    // Check if validation error is in the username field
                    if (err.errors.username) {
                      res.json({ success: false, message: err.errors.username.message }); // Return error
                    } else {
                      // Check if validation error is in the password field
                      if (err.errors.password) {
                        res.json({ success: false, message: err.errors.password.message }); // Return error
                      } else {
                        res.json({ success: false, message: err }); // Return any other error not already covered
                      }
                    }
                  }
                } else {
                  res.json({ success: false, message: 'Could not save user. Error: ', err }); // Return error if not related to validation
                }
              }
            } else {
              res.json({ success: true, message: 'Acount registered!' }); // Return success
            }
          });
        }
      }
    }
  });

  router.get('/checkEmail/:email', (req, res) => {
    if (!req.params.email) {
      res.json({ success: false, message: 'email not provided'});
    } else {
      User.findOne({ email: req.params.email}, (err, user) => {
        if (err) {
          res.json({ success: false, message: err});
        } else {
          if (user) {
            res.json({ success: false, message: 'email taken'});
          } else {
            res.json({ success: true, message: 'email available'});
          }
        }
      });
    }
  });

  router.get('/checkUsername/:username', (req, res) => {
    if (!req.params.username) {
      res.json({ success: false, message: 'username not provided'});
    } else {
      User.findOne({ username: req.params.username}, (err, user) => {
        if (err) {
          res.json({ success: false, message: err});
        } else {
          if (user) {
            res.json({ success: false, message: 'username taken'});
          } else {
            res.json({ success: true, message: 'username available'});
          }
        }
      });
    }
  });

  router.post('/login', (req, res) => {
    if (!req.body.username) {
      res.json({ success: false, message: 'No username was provided'});
    } else {
      if (!req.body.password) {
        res.json({ success: false, message: 'No password was provided'});
      } else {
        User.findOne({ username: req.body.username.toLowerCase() }, (err, user) => {
          if (err) {
            res.json({ success: false, message: err});
          } else {
            if (!user) {
              res.json({ success: false, message: 'No user exist'});
            } else {
              const validPassword = user.comparePassword(req.body.password);
              if (!validPassword) {
                res.json({ success: false, message: 'password invalid'});
              } else {
                const token = jwt.sign({userId: user._id}, config.secret, {expiresIn: '24h'});
                res.json({ success: true, message: 'Success!', token: token, user: {username: user.username}});
              }
            }
          }
        });
      }
    }
  });

// MIDDLEWARE TO INTERCEPT HEADERS
// THIS MIDDLEWARE DECRYPTS THE TOKEN
  router.use((req, res, next) => {
    const token = req.headers['authorization']; // whenever a request coming from angular2 with headers attached it is going to search fot this header
    if (!token) {
      res.json({ success: false, message: 'No token provided'});
    } else {
      jwt.verify(token, config.secret, (err, decoded) => {
        if (err) {
          res.json({ success: false, message: 'invalid token' + err});
        } else {
          req.decoded = decoded;
          next();
        }
      });
    }
  })
// ANY ROUTES COMING AFTER THIS MIDDLEWARE WILL PASS THROUGH THE SAME

// BELOW METHOD TAKES THE DECRYPTED TOKEN FIND THE USER
  router.get('/profile', (req, res) => {
    User.findOne({ _id: req.decoded.userId }).select('username email').exec((err, user) => {
      if (err) {
        res.json({ success: false, message: err});
      } else {
        if (!user) {
          res.json({ success: false, message: 'user not found'});
        } else {
          res.json({ success: true, user: user });
        }
      }
    });
  });

  return router; // Return router object to main index.js
}

这是调用http方法获取用户的服务文件

import { Injectable } from '@angular/core';
import 'rxjs/add/operator/map';
import { Http, Headers, RequestOptions } from '@angular/http';
// import { map } from "rxjs/operators";
// import { map } from 'rxjs/operators';

import { switchMap } from 'rxjs/operators';
import { tokenNotExpired } from 'angular2-jwt';
import { User } from '../shared/user';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
@Injectable()
export class AuthService {

  domain = 'http://localhost:3000';
  authToken;
  user;
  options;

  constructor(private http: Http) { }

  registerUser(user) {
    return this.http.post(this.domain + '/authentication/register', user).map(res => res.json());
  }

  createAuthenticationHeaders() {
    this.loadToken();
    this.options = new RequestOptions({
      headers : new Headers({
        'Content-Type': 'application/json',
        'authorization': this.authToken
      })
    });

  }

  loadToken() {
    this.authToken = localStorage.getItem('token');
  }
  checkUsername(username) {
    return this.http.get(this.domain + '/authentication/checkUsername/' + username).map(res => res.json());
  }

  checkEmail(email) {
    return this.http.get(this.domain + '/authentication/checkEmail/' + email).map(res => res.json());
  }

  login(user) {
    return this.http.post(this.domain + '/authentication/login', user).map(res => res.json());
  }



  logout() {
    this.authToken = null;
    this.user = null;
    localStorage.clear();
  }
  storeUserData(token, user) {
    localStorage.setItem('token', token);
    localStorage.setItem('user', JSON.stringify(user));
    this.authToken = token;
    this.user = user;
  }

  getProfile() {
    this.createAuthenticationHeaders();
    return this.http.get(this.domain + '/authentication/profile', this.options).map(res => res.json());
  }

  checkAdmin(): Observable<User> {
    this.createAuthenticationHeaders();
    return this.http.get(this.domain + '/authentication/profile', this.options).map(res => res.json());
  }

  loggedIn() {
    return tokenNotExpired();
  }
}

这是管理员身份验证保护文件,其中我在canActivate()方法中遇到问题,无法将类型为user的observable转换为boolean的observable

import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRoute, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AuthService } from '../services/auth.service';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable';
import { User } from '../shared/user';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class AdminAuthGuard implements CanActivate {

    redirectUrl;
    constructor(private authService: AuthService, private router: Router) {

    }

    canActivate(router: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
        /*return this.authService.user.switchMap(user => this.authService.getProfile1())
        .map(user => user.isAdmin);*/
        const subject = new Subject();
    // get user access levels
        return this.authService.checkAdmin()
            .map(user => {
            const isAdmin = user.isAdmin;
            if (isAdmin === true ) {
                return true;
            }
            return false;
            });
    }
}

应用程序用户界面

export interface User {
    username: string;
    email: string;
    isAdmin: boolean;
}

2 个答案:

答案 0 :(得分:1)

可观察到的物品需要完成才能激活防护装置。试试:

canActivate(router: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    return this.authService.checkAdmin()
        .map(user => user.isAdmin)
        .first();
}

答案 1 :(得分:-1)

return this.authService.getProfile().map(profile => {
            if (profile.user.isAdmin === true) {
                this.redirectUrl = state.url;
                return true;
            } else {
                return false;
            }
        })