javascript - 如何转换可观察的到可观察的在角度 4
问题描述
我想实现 canActivate() 方法来限制管理路由。我在 checkAdmin 方法(在我的服务文件中)返回用户类型的可观察对象,但 canActivate 方法的返回类型是布尔类型的可观察对象。所以我无法将“用户”类型的可观察值转换为布尔值的可观察值。请帮助我,因为我是角度和平均堆栈的新手
用户模式模型
/* ===================
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);
http 路由,其中包含 /profile 路由以从 mongodb 数据库获取用户
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() 方法中遇到问题,将用户类型的可观察值转换为布尔值的可观察值
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;
}
解决方案
observable 需要完成才能激活警卫。尝试:
canActivate(router: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
return this.authService.checkAdmin()
.map(user => user.isAdmin)
.first();
}
推荐阅读
- javascript - 在二维数组中分配值时如何捕获索引?
- varnish - 在清漆服务器上启用跟踪
- javascript - 使用 codeigniter 进行多个 ajax 调用
- excel - 在打开的工作表中运行 VBA 宏时的错误处理
- javascript - 更改复选框和单选按钮标签的字体大小
- amazon-web-services - 我可以在使用 aws ec2 run-instances 创建实例时标记接口吗?
- javascript - 嵌入式 YouTube API 的递归自定义缩略图不会重播
- python - python3中转换温度的小程序
- authentication - 为什么我的 jsreport 身份验证不起作用?
- c++ - 类构造函数中未定义的长度数组