new here and a very very green react and node dev. My question is as follows:
- Automatic login upon user registration
- I believe this require the API to generate and send a JWS token to the front end. I've a vague idea of what needs to happen but the particulars of how to go about this elude me.
auth controller:
const db = require("../models");
const User = db.user;
const Role = db.role;
var jwt = require("jsonwebtoken");
var bcrypt = require("bcryptjs");
exports.signup = (req, res) => {
const user = new User({
username: req.body.email,
firstname: req.body.firstname,
lastname: req.body.lastname,
email: req.body.email,
password: bcrypt.hashSync(req.body.password, 8),
});
user.save((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
if (req.body.roles) {
Role.find(
{
name: { $in: req.body.roles },
},
(err, roles) => {
if (err) {
res.status(500).send({ message: err });
return;
}
user.roles = roles.map((role) => role._id);
user.save((err) => {
if (err) {
res.status(500).send({ message: err });
return;
}
res.send({ message: "User was registered successfully!" });
});
}
);
} else {
Role.findOne({ name: "user" }, (err, role) => {
if (err) {
res.status(500).send({ message: err });
return;
}
user.roles = [role._id];
user.save((err) => {
if (err) {
res.status(500).send({ message: err });
return;
}
res.send({ message: "User was registered successfully!" });
});
});
}
});
};
exports.signin = (req, res) => {
User.findOne({
email: req.body.email,
})
.populate("roles", "-__v")
.exec((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
if (!user) {
return res.status(404).send({ message: "User Not found." });
}
var passwordIsValid = bcrypt.compareSync(
req.body.password,
user.password
);
if (!passwordIsValid) {
return res.status(401).send({ message: "Invalid Password!" });
}
var token = jwt.sign({ id: user.id }, config.secret, {
expiresIn: 86400, // 24 hours
});
var authorities = [];
for (let i = 0; i < user.roles.length; i ) {
authorities.push("ROLE_" user.roles[i].name.toUpperCase());
}
req.session.token = token;
res.status(200).send({
id: user._id,
username: user.username,
firstname: user.firstname,
lastname: user.lastname,
email: user.email,
roles: authorities,
});
});
};
exports.signout = async (req, res) => {
try {
req.session = null;
return res.status(200).send({ message: "You've been signed out!" });
} catch (err) {
this.next(err);
}
};
auth jwt:
const config = require("../config/auth.config.js");
const db = require("../models");
const User = db.user;
const Role = db.role;
verifyToken = (req, res, next) => {
let token = req.session.token;
if (!token) {
return res.status(403).send({ message: "No token provided!" });
}
jwt.verify(token, config.secret, (err, decoded) => {
if (err) {
return res.status(401).send({ message: "Unauthorized!" });
}
req.userId = decoded.id;
next();
});
};
isAdmin = (req, res, next) => {
User.findById(req.userId).exec((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
Role.find(
{
_id: { $in: user.roles },
},
(err, roles) => {
if (err) {
res.status(500).send({ message: err });
return;
}
for (let i = 0; i < roles.length; i ) {
if (roles[i].name === "admin") {
next();
return;
}
}
res.status(403).send({ message: "Require Admin Role!" });
return;
}
);
});
};
isModerator = (req, res, next) => {
User.findById(req.userId).exec((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
Role.find(
{
_id: { $in: user.roles },
},
(err, roles) => {
if (err) {
res.status(500).send({ message: err });
return;
}
for (let i = 0; i < roles.length; i ) {
if (roles[i].name === "moderator") {
next();
return;
}
}
res.status(403).send({ message: "Require Moderator Role!" });
return;
}
);
});
};
const authJwt = {
verifyToken,
isAdmin,
isModerator,
};
module.exports = authJwt;
front end(metronic react typescript):
/* eslint-disable jsx-a11y/anchor-is-valid */ import {useState, useEffect} from 'react' import {useFormik} from 'formik' import * as Yup from 'yup' import clsx from 'clsx' import {getUserByToken, register} from '../core/_requests' import {Link} from 'react-router-dom' import {toAbsoluteUrl} from '../../../../_metronic/helpers' import {PasswordMeterComponent} from '../../../../_metronic/assets/ts/components' import {useAuth} from '../core/Auth' import React from 'react' const initialValues = { firstname: '', lastname: '', email: '', password: '', changepassword: '', acceptTerms: false, } const registrationSchema = Yup.object().shape({ firstname: Yup.string() .min(3, 'Minimum 3 symbols') .max(50, 'Maximum 50 symbols') .required('First name is required'), email: Yup.string() .email('Wrong email format') .min(3, 'Minimum 3 symbols') .max(50, 'Maximum 50 symbols') .required('Email is required'), lastname: Yup.string() .min(3, 'Minimum 3 symbols') .max(50, 'Maximum 50 symbols') .required('Last name is required'), password: Yup.string() .min(3, 'Minimum 3 symbols') .max(50, 'Maximum 50 symbols') .required('Password is required'), changepassword: Yup.string() .required('Password confirmation is required') .when('password', { is: (val: string) => (val && val.length > 0 ? true : false), then: Yup.string().oneOf([Yup.ref('password')], "Password and Confirm Password didn't match"), }), acceptTerms: Yup.bool().required('You must accept the terms and conditions'), }) export function Registration() { const [loading, setLoading] = useState(false) const {saveAuth, /*setCurrentUser*/} = useAuth() const formik = useFormik({ initialValues, validationSchema: registrationSchema, onSubmit: async (values, {setStatus, setSubmitting}) => { setLoading(true) try { const {data: auth} = await register( values.email, values.firstname, values.lastname, values.password, values.changepassword ) saveAuth(auth) //const {data: user} = await getUserByToken(auth.api_token) //setCurrentUser(user) } catch (error) { console.error(error) saveAuth(undefined) setStatus('The registration details are incorrect') setSubmitting(false) setLoading(false) } }, }) useEffect(() => { PasswordMeterComponent.bootstrap() }, []) return ( <form className='form w-100 fv-plugins-bootstrap5 fv-plugins-framework' noValidate id='kt_login_signup_form' onSubmit={formik.handleSubmit} > {/* begin::Heading */} <div className='mb-10 text-center'> {/* begin::Title */} <h1 className='text-dark mb-3'>Create an Account</h1> {/* end::Title */} {/* begin::Link */} <div className='text-gray-400 fw-bold fs-4'> Already have an account? <Link to='/auth/login' className='link-primary fw-bolder' style={{marginLeft: '5px'}}> Forgot Password ? </Link> </div> {/* end::Link */} </div> {/* end::Heading */} {/* begin::Action */} <button type='button' className='btn btn-light-primary fw-bolder w-100 mb-10'> <img alt='Logo' src={toAbsoluteUrl('/media/svg/brand-logos/google-icon.svg')} className='h-20px me-3' /> Sign in with Google </button> {/* end::Action */} <div className='d-flex align-items-center mb-10'> <div className='border-bottom border-gray-300 mw-50 w-100'></div> <span className='fw-bold text-gray-400 fs-7 mx-2'>OR</span> <div className='border-bottom border-gray-300 mw-50 w-100'></div> </div> {formik.status && ( <div className='mb-lg-15 alert alert-danger'> <div className='alert-text font-weight-bold'>{formik.status}</div> </div> )} {/* begin::Form group Firstname */} <div className='row fv-row mb-7'> <div className='col-xl-6'> <label className='User was registered successfully!" });
because the res.send works like a return you need to send the jwt instead the success message. i hope help youCodePudding user response:
Hey Just Pass The Token to req.body after saving your users like this
exports.signup = (req, res) => { const user = new User({ username: req.body.email, firstname: req.body.firstname, lastname: req.body.lastname, email: req.body.email, password: bcrypt.hashSync(req.body.password, 8), }); user.save((err, user) => { if (err) { res.status(500).send({ message: err }); return; } if (req.body.roles) { Role.find( { name: { $in: req.body.roles }, }, (err, roles) => { if (err) { res.status(500).send({ message: err }); return; } user.roles = roles.map((role) => role._id); user.save((err,data) => { if (err) { res.status(500).send({ message: err }); return; } var token = jwt.sign({ id: data._id }, config.secret, { expiresIn: 86400, // 24 hours }); var authorities = []; // This is what I mean req.session.token = token; res.status(200).send({ id: user._id, username: user.username, firstname: user.firstname, lastname: user.lastname, email: user.email, }); }); }); } ); } else { Role.findOne({ name: "user" }, (err, role) => { if (err) { res.status(500).send({ message: err }); return; } user.roles = [role._id]; user.save((err,data) => { if (err) { res.status(500).send({ message: err }); return; } var token = jwt.sign({ id: data._id }, config.secret, { expiresIn: 86400, // 24 hours }); var authorities = []; // This is what I mean req.session.token = token; res.status(200).send({ id: user._id, username: user.username, firstname: user.firstname, lastname: user.lastname, email: user.email, }); }); }); }); } }); };