我对node.js和Express完全陌生。我想构建一个具有用户管理功能的应用程序。我已经咨询了风暴路径网站(https://stormpath.com/blog/build-nodejs-express-stormpath-app(以及构建并显示的应用程序,如下所示:
欢迎页面屏幕截图
当我单击"立即注册"和"立即登录"时,会发生错误:
寄存器错误屏幕截图
我完全遵循了教程,服务器.js如下所示:
var express = require('express');
var stormpath = require('express-stormpath');
var app = express();
app.set('views', './views');
app.set('view engine', 'jade');
app.use(stormpath.init(app, {
expand: {
customData: true
}
}));
app.get('/', stormpath.getUser, function(req, res) {
res.render('home', {
title: 'Welcome'
});
});
app.use('/profile',stormpath.loginRequired,require('./profile')());
app.on('stormpath.ready',function(){
console.log('Stormpath Ready');
});
app.listen(3000);
索引.Jade如下:
html
head
title=title
link(href='//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css',
rel='stylesheet')
body
div.container
div.jumbotron
h1 Release Control System
if user
p Welcome, #{user.fullName}
p
a.small(href="profile") Edit my profile
form(action='/logout', method='POST')
button.btn.btn-default(type="submit") Logout
else
p Welcome to the release control system , please log in to get started.
p
a.btn.btn-primary(href="/login") Login now
p
span.small Don't have an account?
span
a.small(href="/register") Register now
和paackage.json,
{
"name": "sampple",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www"
},
"dependencies": {
"body-parser": "~1.16.0",
"cookie-parser": "~1.4.3",
"debug": "~2.6.0",
"express": "~4.14.1",
"jade": "~1.11.0",
"morgan": "~1.7.0",
"serve-favicon": "~2.3.2"
},
"description": "Release control",
"main": "server.js",
"devDependencies": {},
"author": "",
"license": "MIT"
}
请告知应修改的位置以修复错误,包括按"立即登录"按钮。
任何建议都值得赞赏,因为我不熟悉node.js和Express框架,我想实现用户管理,谢谢。
我在Stormpath工作。只需最少的设置即可使快速风暴路径与应用程序配合使用。npm install express-stormpath
并添加var stormpath = require('express-stormpath');
后,您只需要再做两件事:
// Tell your express app to use Stormpath
app.use(stormpath.init(app, {
// Add optional configuration settings here
expand: {
customData: true
}
}));
// Wait for Stormpath to tell you it's ready
app.on('stormpath.ready',function(){
console.log('Stormpath Ready');
});
完成这些步骤后,您将自动获得开箱即用的/register、/login、/me、/verify 和/forget(以及这些路由的默认视图(。我们的快速入门中对此进行了介绍,你可以在此处进行操作:https://docs.stormpath.com/nodejs/express/latest/setup.html
本教程介绍如何设置一个真正基本的快速项目,该项目有一个额外的视图,即登录用户的配置文件页面。下面是直接从教程中复制/粘贴的代码。让我知道这是否适合您。
服务器.js:
var express = require('express'); var stormpath = require('express-stormpath');
var app = express();
app.set('views', './views'); app.set('view engine', 'jade');
app.use(stormpath.init(app, { expand: {
customData: true } }));
app.get('/', stormpath.getUser, function(req, res) { res.render('home', {
title: 'Welcome' }); });
app.on('stormpath.ready',function(){ console.log('Stormpath Ready'); });
app.listen(3000);
简介.js:
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var csurf = require('csurf');
var express = require('express');
var extend = require('xtend');
var forms = require('forms');
var collectFormErrors = require('express-stormpath/lib/helpers').collectFormErrors;
// Declare the schema of our form:
var profileForm = forms.create({
givenName: forms.fields.string({
required: true
}),
surname: forms.fields.string({ required: true }),
streetAddress: forms.fields.string(),
city: forms.fields.string(),
state: forms.fields.string(),
zip: forms.fields.string()
});
// A render function that will render our form and
// provide the values of the fields, as well
// as any situation-specific locals
function renderForm(req,res,locals){
res.render('profile', extend({
title: 'My Profile',
csrfToken: req.csrfToken(),
givenName: req.user.givenName,
surname: req.user.surname,
streetAddress: req.user.customData.streetAddress,
city: req.user.customData.city,
state: req.user.customData.state,
zip: req.user.customData.zip
},locals||{}));
}
// Export a function which will create the
// router and return it
module.exports = function profile(){
var router = express.Router();
router.use(cookieParser());
router.use(bodyParser.urlencoded({ extended: true }));
router.use(csurf({ cookie: true }));
// Capture all requests, the form library will negotiate
// between GET and POST requests
router.all('/', function(req, res) {
profileForm.handle(req,{
success: function(form){
// The form library calls this success method if the
// form is being POSTED and does not have errors
// The express-stormpath library will populate req.user,
// all we have to do is set the properties that we care
// about and then cal save() on the user object:
req.user.givenName = form.data.givenName;
req.user.surname = form.data.surname;
req.user.customData.streetAddress = form.data.streetAddress;
req.user.customData.city = form.data.city;
req.user.customData.state = form.data.state;
req.user.customData.zip = form.data.zip;
req.user.customData.save();
req.user.save(function(err){
if(err){
if(err.developerMessage){
console.error(err);
}
renderForm(req,res,{
errors: [{
error: err.userMessage ||
err.message || String(err)
}]
});
}else{
renderForm(req,res,{
saved:true
});
}
});
},
error: function(form){
// The form library calls this method if the form
// has validation errors. We will collect the errors
// and render the form again, showing the errors
// to the user
renderForm(req,res,{
errors: collectFormErrors(form)
});
},
empty: function(){
// The form library calls this method if the
// method is GET - thus we just need to render
// the form
renderForm(req,res);
}
});
});
// This is an error handler for this router
router.use(function (err, req, res, next) {
// This handler catches errors for this router
if (err.code === 'EBADCSRFTOKEN'){
// The csurf library is telling us that it can't
// find a valid token on the form
if(req.user){
// session token is invalid or expired.
// render the form anyways, but tell them what happened
renderForm(req,res,{
errors:[{error:'Your form has expired. Please try again.'}]
});
}else{
// the user's cookies have been deleted, we dont know
// their intention is - send them back to the home page
res.redirect('/');
}
}else{
// Let the parent app handle the error
return next(err);
}
});
return router;
};
视图/首页.翡翠:
html
head
title=title
link(href='//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css', rel='stylesheet')
body
div.container
div.jumbotron
h1 Hello!
if user
p Welcome, #{user.fullName}
p
a.small(href="profile") Edit my profile
form(action='/logout', method='POST')
button.btn.btn-default(type="submit") Logout
else
p Welcome to my app, ready to get started?
p
a.btn.btn-primary(href="/login") Login now
p
span.small Don't have an account?
span
a.small(href="/register") Register now
views/profile.jade:
html
head
title=title
link(
href='//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css',
rel='stylesheet'
)
body
div.container
div.page-header
h1 My Profile
if errors
each error in errors
div.alert.alert-danger
span #{error.error}
if saved
div.alert.alert-success
span Your profile has been saved
form.login-form.form-horizontal(method='post', role='form')
input(name='_csrf', type='hidden', value=csrfToken)
div.form-group
label.col-sm-4 First Name
div.col-sm-8
input.form-control(
placeholder='Your first name',
required=true,
name='givenName',
type='text',
value=givenName)
div.form-group
label.col-sm-4 Last Name
div.col-sm-8
input.form-control(placeholder='Your last name',
required=true,
name='surname',
type='text',
value=surname)
div.form-group
label.col-sm-4 Street address
div.col-sm-8
input.form-control(placeholder='e.g. 123 Sunny Ave',
required=true,
name='streetAddress',
type='text',
value=streetAddress)
div.form-group
label.col-sm-4 City
div.col-sm-8
input.form-control(placeholder='e.g. City',
required=true,
name='city',
type='text',
value=city)
div.form-group
label.col-sm-4 State
div.col-sm-8
input.form-control(placeholder='e.g. CA',
required=true,
name='state',
type='text',
value=state)
div.form-group
label.col-sm-4 ZIP
div.col-sm-8
input.form-control(placeholder='e.g. 94116',
required=true,
name='zip',
type='text',
value=zip)
div.form-group
div.col-sm-offset-4.col-sm-8
button.login.btn.btn-primary(type='submit') Save
div.pull-right
a(href="/") Return to home page