我想实现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;
}
答案 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;
}
})