我有一个简单的MEAN堆栈应用程序,只是尝试了解身份验证并使其工作。
您可以在github中查看完整的程序:https://github.com/7seven7lst/chatterApp
我在Angular(app.js)中有以下内容,其中配置文件路由受到限制:
angular.module('chat', ['ui.router', 'chat.main', 'chat.signin', 'chat.profile'])
.config(function($stateProvider, $urlRouterProvider, $httpProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('home', {
url: '/',
templateUrl: 'views/main.html',
controller: 'MainCtrl'
})
.state('signin', {
url: '/signin',
templateUrl: 'views/signin.html',
controller: 'SigninCtrl'
})
.state('profile', {
url: '/profile',
templateUrl: 'views/profile.html',
controller: 'ProfileCtrl'
});
// the following will give angular injection error
/*
$httpProvider.interceptors.push(function($q, $state) {
return {
response: function(response) {
// do something on success
return response;
},
responseError: function(response) {
if (response.status === 401) {
$state.go('home');
}
return $q.reject(response);
}
};
});
*/
});
我有NodeJS功能来处理身份验证:
var express = require('express');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var path = require('path');
var session = require('express-session');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
// setup passport
passport.use(new LocalStrategy(
function(username, password, done){
if (username !== 'test' || password !='password'){
console.log("not loged in ");
return done(null, false); // login failed
} else {
console.log("somehow we are here");
return done(null, {username: username});
}
}
));
passport.serializeUser(function(user, done){
done(null, user);
});
passport.deserializeUser(function(user, done){
done(null, user);
})
// middleware function to handle protected route
var requireAuthentication = function(req, res, next){
if (req.isAuthenticated()){
next();
} else {
console.log("401 should be sent here...");
res.end(401);
//res.redirect('/login');
}
}
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false })); // middleware to parse the form data
app.use(express.static(__dirname + '/public')); // server static file in public folder.
app.use('/bower_components', express.static(__dirname + '/bower_components'));
app.use(cookieParser());
app.use(session({
secrete: 'make this a good secret',
resave: false,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
app.get('/', function(req, res){
console.log("here, homepage");
res.sendFile('index.html');
})
app.post('/signin', passport.authenticate('local', {
successRedirect: '/profile', failureRedirect: '/login'
}), function(req, res){
res.send(req.user);
});
app.get('/profile', [requireAuthentication,
function(req, res){
console.log("here, profile page");
res.json(200, {username: req.session.passport.user.username});
}])
app.get('*', function(req, res){
res.redirect('/');
})
app.listen(8080, function(){
console.log("listening on port 8080");
})
我测试了我的应用程序,并且没有从服务器发送过401。如果我试图取消注释上面的线条,角度拦截器似乎不起作用。 如何让受保护的路线在anuglar工作?
答案 0 :(得分:2)
从查看存储库代码看,signin.html
中的表单似乎试图在提交时调用signin
函数。此功能未定义,因此没有请求发送到服务器,因此没有响应。
编辑:
处理MEAN应用程序的身份验证时,有两个单独的注意事项。在服务器和客户端上完成身份验证。
服务器强>
在服务器上,对于已使用requireAuthentication
中间件的路由,如果用户未经过身份验证,客户端将收到401状态代码响应。
如果您输入localhost:8080/profile
,则在浏览器中,您将收到服务器的401响应。
<强>客户端强>
在客户端上,因为您未指定要使用html5mode。客户端路由使用片段url(以#
开头的url部分)完成。 url的那部分不会发送到服务器。如果您向localhost:8080/#/profile
发出请求,则服务器在http请求中获取的路径为/
。
在服务器上配置了/
路由,以便在您的情况下使用index.html
文件进行响应。然后index.html
发出加载角度脚本并运行客户端代码的请求。
此时ui.router
将处理客户端路由。这是您需要在客户端上进行身份验证检查的地方。有几种策略用于指示状态需要认证。
一种方法是在实际的状态定义上加上标记:
$stateProvider
.state('home', {
url: '/', // is actually /#/
templateUrl: 'views/main.html',
controller: 'MainCtrl'
})
...
.state('profile', {
url: '/profile', // is actually /#/profile
templateUrl: 'views/profile.html',
controller: 'ProfileCtrl',
authRequired: true
});
然后添加一个运行块,为stateChangeStart
事件添加一个listencope:
app.run(function($rootScope, $state, Auth) {
$rootScope.$on('$stateChangeStart', function(event, nextState, params) {
if (nextState.authRequired && !Auth.isAuthenticated()) {
$state.go('signin');
}
});
});
auth服务需要知道用户是否经过身份验证,可能需要第一次进行服务器往返。 stackoverflow上有很多关于如何做到这一点的答案。
另一部分是$httpProvider.interceptors
部分。从您的角度客户端,如果您向服务器请求需要身份验证的路由,请在示例中/profile
(不是/#/profile
,请记住这只是/
),并且您是未经过身份验证,您将收到401
响应。 auth拦截器部分告诉角度客户端如何在这种情况下做出响应。
.config(function($stateProvider, $urlRouterProvider, $httpProvider, $injector) {
...
$httpProvider.interceptors.push(function($q) {
return {
responseError: function(response) {
if (response.status === 401) {
$injector.get('$state').go('signin');
}
return $q.reject(response);
}
};
});
});