I'm working to get passport-http
working with my application to make it comply with RESTful
principles.
Right now the default is that the browser prompts the user for a username and password with it's own prompt.
With Node.js and PassportJS is it possible to use my own login form? In the case that a user tries to access a page that they are not authenticated for then I would redirect them to that form. Or is this in itself violating the principles of RESTful
design?
REST defines web services. Services are UI agnostic.
In theory, you should be testing your services with a tool such as fiddler, firebug, postman or something similar.
Your UI choices are completely separate.
If you need someone to be able to authenticate, then you will need to handle the visual presentation of the request to user to authenticate.
If you look at the documentation of passport, they show an example of basic authentication:
app.post('/login', passport.authenticate('local', { successRedirect: '/', failureRedirect: '/login'}));
In this case, the authenticate will redirect the user to the page defined at the root of the website if successful, else the user will be redirected to a page served at /login.
In either case, the login attempt is a post method that comes from a page served by the webserver.
passportjs docs
This is what you need in your server file to create user and password authentication. you need to include the localStategy, configure passport, and use the serialize and deserialize methods. The below works.
var express = require("express");
var app = express();
var passport = require("passport");
var flash = require("connect-flash");
var LocalStrategy = require("passport-local").Strategy;
var mongoose = require("mongoose");
var bodyParser = require("body-parser");
var session = require("express-session");
var cookieParser = require("cookie-parser");
app.use(bodyParser.urlencoded({extended : false}));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(session({
secret : "keyboard cat",
resave : false,
saveUninitialized : true
}))
app.use(flash());
app.use(passport.initialize());
app.use(passport.session());
mongoose.connect("mongodb://localhost/passport", function(){
console.log("connected")
})
var userSchema = new mongoose.Schema({
username : String,
password : String,
})
userSchema.methods.validPassword = function(pwd){
return (this.password === pwd)
}
var User = mongoose.model("User", userSchema)
passport.use("local", new LocalStrategy(
function(username, password, done){
User.findOne({ username : username}, function(err, user){
if(err){return done(err);}
if(!user){
console.log("no user")
return done(null, false,{message : "Incorrect username."});
}
if(!user.validPassword(password)){
return done(null, false,{message : "Incorrect password."});
}
return done(null, user)
})
}))
passport.serializeUser(function(user, done){ // change done to cb
done(null, user);
})
passport.deserializeUser(function(user, done){
User.findOne(user, function(err, user){
console.log("myerr" + err)
done(err, user)
})
})
app.set("views", "./views");
app.set("view engine", "jade");
app.get("/signup", function(req, res){
res.render("signup")
})
app.post("/signup", function(req, res){
User.create({"username" : req.body.username, "password" : req.body.password}, function(err, doc){
console.log(doc);
})
res.redirect("/login")
})
app.get("/login", function(req, res){
res.render("login")
})
app.post("/login", function(req, res, next){
passport.authenticate("local", function(err, user, info){
if(err){return next(err); }
if(!user){return res.redirect("/login");}
req.logIn(user, function(err){
if(err){ return next(err);}
return res.redirect("/users/" + user.username)
})
})(req, res, next);
})
app.get("*", function(req, res){
res.send("EVERYTHANG")
})
app.listen(3000, function(){
console.log("listening on 3000")
})
login.jade:
html
head
title LogIN
body
form(method = "POST", action = "/login")
label username
input(type = "text", name = "username")
br
label password :
input(type = "text", name = "password")
button(type="submit") LogIN
signup.jade:
html
head
title signup
body
form(method = "POST", action= "/signup")
label username
input(type = "text", name = "username")
br
label password :
input(type = "text" , name = "password")
button(type="submit") Signup
For REST I would suggest you to use HTTP Basic/Digest authentication with HTTPS and you can use http-auth to implement that:
// Authentication module.
var auth = require('http-auth');
var basic = auth.basic({
realm: "Simon Area.",
file: __dirname + "/../data/users.htpasswd" // gevorg:gpass, Sarah:testpass ...
});
// Application setup.
var app = express();
// Setup strategy.
var passport = require('passport');
passport.use(auth.passport(basic));
// Setup route.
app.get('/', passport.authenticate('http', { session: false }), function(req, res) {
res.end("Welcome to private area - " + req.user + "!");
});
or you can use it without passport:
// Authentication module.
var auth = require('http-auth');
var basic = auth.basic({
realm: "Simon Area.",
file: __dirname + "/../data/users.htpasswd" // gevorg:gpass, Sarah:testpass ...
});
// Application setup.
var app = express();
app.use(auth.connect(basic));
// Setup route.
app.get('/', function(req, res){
res.send("Hello from express - " + req.user + "!");
});