wip: move all authentication to passport, including JWT and add new AccessToken and RefreshToken (which are not issued yet)
This commit is contained in:
parent
fc99d8a03b
commit
254b262a72
40
api/package-lock.json
generated
40
api/package-lock.json
generated
|
@ -6243,6 +6243,16 @@
|
||||||
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
|
||||||
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
|
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
|
||||||
},
|
},
|
||||||
|
"oauth2orize": {
|
||||||
|
"version": "1.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/oauth2orize/-/oauth2orize-1.11.0.tgz",
|
||||||
|
"integrity": "sha1-eTzvJR1F696sMq5AqLaBT6qx1IM=",
|
||||||
|
"requires": {
|
||||||
|
"debug": "2.x.x",
|
||||||
|
"uid2": "0.0.x",
|
||||||
|
"utils-merge": "1.x.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
"object-assign": {
|
"object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
|
@ -6471,6 +6481,31 @@
|
||||||
"pause": "0.0.1"
|
"pause": "0.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"passport-custom": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/passport-custom/-/passport-custom-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-/2m7jUGxmCYvoqenLB9UrmkCgPt64h8ZtV+UtuQklZ/Tn1NpKBeOorCYkB/8lMRoiZ5hUrCoMmDtxCS/d38mlg==",
|
||||||
|
"requires": {
|
||||||
|
"passport-strategy": "1.x.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"passport-http-bearer": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/passport-http-bearer/-/passport-http-bearer-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-FHRp6jZp4qhMYWfvmdu3fh8AmKg=",
|
||||||
|
"requires": {
|
||||||
|
"passport-strategy": "1.x.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"passport-jwt": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-BwC0n2GP/1hMVjR4QpnvqA61TxenUMlmfNjYNgK0ZAs0HK4SOQkHcSv4L328blNTLtHq7DbmvyNJiH+bn6C5Mg==",
|
||||||
|
"requires": {
|
||||||
|
"jsonwebtoken": "^8.2.0",
|
||||||
|
"passport-strategy": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"passport-local": {
|
"passport-local": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz",
|
||||||
|
@ -8566,6 +8601,11 @@
|
||||||
"random-bytes": "~1.0.0"
|
"random-bytes": "~1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"uid2": {
|
||||||
|
"version": "0.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz",
|
||||||
|
"integrity": "sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I="
|
||||||
|
},
|
||||||
"undefsafe": {
|
"undefsafe": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz",
|
||||||
|
|
|
@ -41,8 +41,12 @@
|
||||||
"mongoose-unique-validator": "2.0.3",
|
"mongoose-unique-validator": "2.0.3",
|
||||||
"morgan": "1.10.0",
|
"morgan": "1.10.0",
|
||||||
"nodemailer": "^6.4.18",
|
"nodemailer": "^6.4.18",
|
||||||
|
"oauth2orize": "^1.11.0",
|
||||||
"passport": "0.4.1",
|
"passport": "0.4.1",
|
||||||
"passport-local": "1.0.0",
|
"passport-custom": "^1.1.1",
|
||||||
|
"passport-http-bearer": "^1.0.1",
|
||||||
|
"passport-jwt": "^4.0.0",
|
||||||
|
"passport-local": "^1.0.0",
|
||||||
"request": "2.88.2",
|
"request": "2.88.2",
|
||||||
"sanitize-filename": "^1.6.3",
|
"sanitize-filename": "^1.6.3",
|
||||||
"slug": "^3.5.2",
|
"slug": "^3.5.2",
|
||||||
|
|
|
@ -1,13 +1,20 @@
|
||||||
const passport = require('passport');
|
const passport = require('passport');
|
||||||
const LocalStrategy = require('passport-local').Strategy;
|
const { Strategy: LocalStrategy } = require('passport-local');
|
||||||
const mongoose = require('mongoose');
|
const { Strategy: BearerStrategy } = require('passport-http-bearer');
|
||||||
const User = mongoose.model('User');
|
const { Strategy: JwtStrategy } = require('passport-jwt');
|
||||||
|
const { Strategy: CustomStrategy } = require('passport-custom');
|
||||||
|
|
||||||
|
const { User, AccessToken, RefreshToken } = require('../models');
|
||||||
|
|
||||||
|
const secret = require('../config').secret;
|
||||||
|
|
||||||
passport.use(
|
passport.use(
|
||||||
|
'usernameAndPassword',
|
||||||
new LocalStrategy(
|
new LocalStrategy(
|
||||||
{
|
{
|
||||||
usernameField: 'user[email]',
|
usernameField: 'user[email]',
|
||||||
passwordField: 'user[password]',
|
passwordField: 'user[password]',
|
||||||
|
session: false,
|
||||||
},
|
},
|
||||||
async function (email, password, done) {
|
async function (email, password, done) {
|
||||||
try {
|
try {
|
||||||
|
@ -16,10 +23,6 @@ passport.use(
|
||||||
return done(null, false, { errors: { 'email or password': 'is invalid' } });
|
return done(null, false, { errors: { 'email or password': 'is invalid' } });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.needsEmailValidation) {
|
|
||||||
return done(null, false, { errors: { 'E-Mail-Bestätigung': 'noch nicht erfolgt' } });
|
|
||||||
}
|
|
||||||
|
|
||||||
return done(null, user);
|
return done(null, user);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
done(err);
|
done(err);
|
||||||
|
@ -27,3 +30,153 @@ passport.use(
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function getRequestToken(req) {
|
||||||
|
const authorization = req.headers.authorization;
|
||||||
|
if (typeof authorization !== 'string') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [tokenType, token] = authorization.split(' ');
|
||||||
|
|
||||||
|
if (tokenType === 'Token' || tokenType === 'Bearer') {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
passport.use(
|
||||||
|
'jwt',
|
||||||
|
new JwtStrategy(
|
||||||
|
{
|
||||||
|
secretOrKey: secret,
|
||||||
|
jwtFromRequest: getRequestToken,
|
||||||
|
algorithms: ['HS256'],
|
||||||
|
},
|
||||||
|
async function (token, done) {
|
||||||
|
try {
|
||||||
|
// we used to put the user ID into the token directly :(
|
||||||
|
const {id} = token
|
||||||
|
const user = await User.findById(id);
|
||||||
|
return done(null, user || false);
|
||||||
|
} catch (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
passport.use(
|
||||||
|
'accessToken',
|
||||||
|
new BearerStrategy(async function (token, done) {
|
||||||
|
try {
|
||||||
|
const accessToken = await AccessToken.findOne({ token }).populate('user');
|
||||||
|
if (accessToken && accessToken.user) {
|
||||||
|
// TODO: scope
|
||||||
|
return done(null, user, { scope: accessToken.scope });
|
||||||
|
} else {
|
||||||
|
return done(null, false);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
passport.use(
|
||||||
|
'refreshToken',
|
||||||
|
new BearerStrategy(async function (token, done) {
|
||||||
|
try {
|
||||||
|
const refreshToken = await RefreshToken.findOne({ token }).populate('user');
|
||||||
|
if (refreshToken && refreshToken.user) {
|
||||||
|
// TODO: scope
|
||||||
|
return done(null, user, { scope: 'auth.refresh' });
|
||||||
|
} else {
|
||||||
|
return done(null, false);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
passport.use(
|
||||||
|
'userId',
|
||||||
|
new CustomStrategy(async (req, callback) => {
|
||||||
|
try {
|
||||||
|
let userId;
|
||||||
|
|
||||||
|
const headerToken = getRequestToken(req);
|
||||||
|
if (headerToken && headerToken.length === 24) {
|
||||||
|
userId = headerToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!userId) {
|
||||||
|
const bodyId = req.body && req.body.id;
|
||||||
|
if (bodyId && bodyId.length === 24) {
|
||||||
|
userId = bodyId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let user;
|
||||||
|
if (userId) {
|
||||||
|
user = await User.findById(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(null, user || false);
|
||||||
|
} catch (err) {
|
||||||
|
callback(err);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function creates a middleware that does a passport authentication.
|
||||||
|
*/
|
||||||
|
function createMiddleware(strategies, required) {
|
||||||
|
return (req, res, next) => {
|
||||||
|
passport.authenticate(strategies, { session: false }, (err, user, info) => {
|
||||||
|
// If this authentication produced an error, throw it. In a chain of
|
||||||
|
// multiple strategies, errors are ignored, unless every strategy errors.
|
||||||
|
if (required && err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If you *must* be logged in for this action, require a user.
|
||||||
|
if (required && !user) {
|
||||||
|
return res.sendStatus(403);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regardless of whether login is required, if you're logged in as an
|
||||||
|
// unverified user, produce an error.
|
||||||
|
if (user && user.needsEmailValidation) {
|
||||||
|
return res.status(403).json({ errors: { 'E-Mail-Bestätigung': 'noch nicht erfolgt' } });
|
||||||
|
}
|
||||||
|
|
||||||
|
req.user = user
|
||||||
|
req.authInfo = info
|
||||||
|
req.scope = (info && info.scope) || '*'
|
||||||
|
|
||||||
|
return next();
|
||||||
|
})(req, res, next);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// these are the standard authentication mechanisms, for when you want user
|
||||||
|
// information in the route, and either require a login, or don't care
|
||||||
|
optional: createMiddleware(['jwt', 'accessToken'], false),
|
||||||
|
required: createMiddleware(['jwt', 'accessToken'], true),
|
||||||
|
|
||||||
|
// required to check username and passwort for generating a new token, e.g.
|
||||||
|
// on the /users/login route, and later on oauth routes
|
||||||
|
usernameAndPassword: createMiddleware('usernameAndPassword', true),
|
||||||
|
|
||||||
|
// will be used to verify a refresh token on the route that will exchange the
|
||||||
|
// refresh token for a new access token (not in use yet)
|
||||||
|
refreshToken: createMiddleware('refreshToken', true),
|
||||||
|
|
||||||
|
// for track upload, we still allow "userId" for a while
|
||||||
|
requiredWithUserId: createMiddleware(['jwt', 'accessToken', 'userId'], true),
|
||||||
|
};
|
||||||
|
|
|
@ -4,16 +4,18 @@ const bodyParser = require('body-parser');
|
||||||
const session = require('express-session');
|
const session = require('express-session');
|
||||||
const cors = require('cors');
|
const cors = require('cors');
|
||||||
const errorhandler = require('errorhandler');
|
const errorhandler = require('errorhandler');
|
||||||
const auth = require('./routes/auth');
|
const passport = require('passport');
|
||||||
|
|
||||||
|
require('./config/passport')
|
||||||
|
|
||||||
const isProduction = process.env.NODE_ENV === 'production';
|
const isProduction = process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
// Create global app object
|
// Create global app object
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
|
|
||||||
app.use(cors());
|
app.use(cors());
|
||||||
app.use(auth.getUserIdMiddleware);
|
app.use(passport.initialize());
|
||||||
app.use(auth.loadUserMiddleware);
|
|
||||||
|
|
||||||
// Normal express config defaults
|
// Normal express config defaults
|
||||||
app.use(require('morgan')('dev'));
|
app.use(require('morgan')('dev'));
|
||||||
|
|
47
api/src/models/AccessToken.js
Normal file
47
api/src/models/AccessToken.js
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
const mongoose = require('mongoose');
|
||||||
|
const uniqueValidator = require('mongoose-unique-validator');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
const schema = new mongoose.Schema(
|
||||||
|
{
|
||||||
|
token: { index: true, type: String, required: true, unique: true },
|
||||||
|
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
|
||||||
|
expiresAt: { type: Date, required: true },
|
||||||
|
scope: { type: String, required: true, defaultValue: '*' },
|
||||||
|
},
|
||||||
|
{ timestamps: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
schema.plugin(uniqueValidator, { message: 'reused token' });
|
||||||
|
|
||||||
|
class AccessToken extends mongoose.Model {
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
token: this.token,
|
||||||
|
expires: this.expires,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid() {
|
||||||
|
return this.expiresAt < new Date()
|
||||||
|
}
|
||||||
|
|
||||||
|
toHeaderString() {
|
||||||
|
return 'Bearer ' + this.token;
|
||||||
|
}
|
||||||
|
|
||||||
|
static generate(user, scope = '*', expiresInSeconds = 24 * 60 * 60) {
|
||||||
|
const token = crypto.randomBytes(32).toString('hex');
|
||||||
|
|
||||||
|
return new AccessToken({
|
||||||
|
token,
|
||||||
|
user,
|
||||||
|
expiresAt: new Date(new Date().getTime() + 1000 * expiresInSeconds),
|
||||||
|
scope,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mongoose.model(AccessToken, schema);
|
||||||
|
|
||||||
|
module.exports = AccessToken;
|
49
api/src/models/RefreshToken.js
Normal file
49
api/src/models/RefreshToken.js
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
const mongoose = require('mongoose');
|
||||||
|
const uniqueValidator = require('mongoose-unique-validator');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
const AccessToken = require('./AccessToken')
|
||||||
|
|
||||||
|
const schema = new mongoose.Schema(
|
||||||
|
{
|
||||||
|
token: { index: true, type: String, required: true, unique: true },
|
||||||
|
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
|
||||||
|
expiresAt: { type: Date, required: false },
|
||||||
|
scope: { type: String, required: true, defaultValue: '*' },
|
||||||
|
},
|
||||||
|
{ timestamps: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
schema.plugin(uniqueValidator, { message: 'reused token' });
|
||||||
|
|
||||||
|
class RefreshToken extends mongoose.Model {
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
token: this.token,
|
||||||
|
expires: this.expires,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid() {
|
||||||
|
return this.expiresAt == null || this.expiresAt < new Date()
|
||||||
|
}
|
||||||
|
|
||||||
|
static generate(user, scope = '*', expiresInSeconds = 24 * 60 * 60) {
|
||||||
|
const token = crypto.randomBytes(32).toString('hex');
|
||||||
|
|
||||||
|
return new RefreshToken({
|
||||||
|
token,
|
||||||
|
user,
|
||||||
|
expiresAt: new Date(new Date().getTime() + 1000 * expiresInSeconds),
|
||||||
|
scope,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
genererateAccessToken(expiresInSeconds = undefined) {
|
||||||
|
return AccessToken.generate(this.user, this.scope, expiresInSeconds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mongoose.model(RefreshToken, schema);
|
||||||
|
|
||||||
|
module.exports = RefreshToken;
|
6
api/src/models/index.js
Normal file
6
api/src/models/index.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
module.exports.AccessToken = require('./AccessToken')
|
||||||
|
module.exports.Comment = require('./Comment')
|
||||||
|
module.exports.RefreshToken = require('./RefreshToken')
|
||||||
|
module.exports.Track = require('./Track')
|
||||||
|
module.exports.TrackData = require('./TrackData')
|
||||||
|
module.exports.User = require('./User')
|
|
@ -2,7 +2,7 @@ const router = require('express').Router();
|
||||||
const mongoose = require('mongoose');
|
const mongoose = require('mongoose');
|
||||||
const User = mongoose.model('User');
|
const User = mongoose.model('User');
|
||||||
const wrapRoute = require('../../_helpers/wrapRoute');
|
const wrapRoute = require('../../_helpers/wrapRoute');
|
||||||
const auth = require('../auth');
|
const auth = require('../../config/passport');
|
||||||
|
|
||||||
// Preload user profile on routes with ':username'
|
// Preload user profile on routes with ':username'
|
||||||
router.param('username', async function (req, res, next, username) {
|
router.param('username', async function (req, res, next, username) {
|
||||||
|
|
|
@ -5,7 +5,7 @@ const Track = mongoose.model('Track');
|
||||||
const Comment = mongoose.model('Comment');
|
const Comment = mongoose.model('Comment');
|
||||||
const User = mongoose.model('User');
|
const User = mongoose.model('User');
|
||||||
const busboy = require('connect-busboy');
|
const busboy = require('connect-busboy');
|
||||||
const auth = require('../auth');
|
const auth = require('../../config/passport');
|
||||||
const { normalizeUserAgent, buildObsver1 } = require('../../logic/tracks');
|
const { normalizeUserAgent, buildObsver1 } = require('../../logic/tracks');
|
||||||
const wrapRoute = require('../../_helpers/wrapRoute');
|
const wrapRoute = require('../../_helpers/wrapRoute');
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ async function getMultipartOrJsonBody(req, mapJsonBody = (x) => x) {
|
||||||
|
|
||||||
router.post(
|
router.post(
|
||||||
'/',
|
'/',
|
||||||
auth.required,
|
auth.requiredWithUserId,
|
||||||
busboy(), // parse multipart body
|
busboy(), // parse multipart body
|
||||||
wrapRoute(async (req, res) => {
|
wrapRoute(async (req, res) => {
|
||||||
// Read the whole file into memory. This is not optimal, instead, we should
|
// Read the whole file into memory. This is not optimal, instead, we should
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
const router = require('express').Router();
|
const router = require('express').Router();
|
||||||
const passport = require('passport');
|
const passport = require('passport');
|
||||||
const wrapRoute = require('../../_helpers/wrapRoute');
|
const wrapRoute = require('../../_helpers/wrapRoute');
|
||||||
const auth = require('../auth');
|
const auth = require('../../config/passport');
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
'/user',
|
'/user',
|
||||||
|
@ -42,27 +42,11 @@ router.put(
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
router.post('/users/login', function (req, res, next) {
|
router.post('/users/login',
|
||||||
if (!req.body.user.email) {
|
auth.usernameAndPassword,
|
||||||
return res.status(422).json({ errors: { email: "can't be blank" } });
|
wrapRoute((req, res) => {
|
||||||
}
|
return res.json({ user: req.user.toAuthJSON() });
|
||||||
|
}),
|
||||||
if (!req.body.user.password) {
|
);
|
||||||
return res.status(422).json({ errors: { password: "can't be blank" } });
|
|
||||||
}
|
|
||||||
|
|
||||||
passport.authenticate('local', { session: false }, function (err, user, info) {
|
|
||||||
if (err) {
|
|
||||||
return next(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user) {
|
|
||||||
user.token = user.generateJWT();
|
|
||||||
return res.json({ user: user.toAuthJSON() });
|
|
||||||
} else {
|
|
||||||
return res.status(422).json(info);
|
|
||||||
}
|
|
||||||
})(req, res, next);
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
const jwt = require('express-jwt');
|
const passport = require('passport')
|
||||||
|
const {LocalStrategy} = require('passport-local')
|
||||||
const secret = require('../config').secret;
|
const secret = require('../config').secret;
|
||||||
const User = require('../models/User');
|
const User = require('../models/User');
|
||||||
|
|
||||||
|
@ -27,19 +28,13 @@ async function getUserIdMiddleware(req, res, next) {
|
||||||
const [tokenType, token] = (authorization && authorization.split(' ')) || [];
|
const [tokenType, token] = (authorization && authorization.split(' ')) || [];
|
||||||
|
|
||||||
if (tokenType === 'Token' || tokenType === 'Bearer') {
|
if (tokenType === 'Token' || tokenType === 'Bearer') {
|
||||||
|
|
||||||
// only parse the token as jwt if it looks like one, otherwise we get an error
|
// only parse the token as jwt if it looks like one, otherwise we get an error
|
||||||
return jwtOptional(req, res, next);
|
return jwtOptional(req, res, next);
|
||||||
|
|
||||||
} else if (tokenType === 'OBSUserId') {
|
} else if (tokenType === 'OBSUserId') {
|
||||||
req.authInfo = { id: token.trim() };
|
req.authInfo = { id: token.trim() };
|
||||||
next();
|
next();
|
||||||
} else if (!authorization && req.body && req.body.id && req.body.id.length === 24) {
|
|
||||||
const user = await User.findById(req.body.id);
|
|
||||||
if (user) {
|
|
||||||
req.authInfo = { id: user.id };
|
|
||||||
req.user = user;
|
|
||||||
}
|
|
||||||
next();
|
|
||||||
} else {
|
|
||||||
req.authInfo = null;
|
req.authInfo = null;
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
@ -48,33 +43,3 @@ async function getUserIdMiddleware(req, res, next) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadUserMiddleware(req, res, next) {
|
|
||||||
try {
|
|
||||||
if (req.authInfo && req.authInfo.id) {
|
|
||||||
req.user = await User.findById(req.authInfo.id);
|
|
||||||
|
|
||||||
if (!req.user) {
|
|
||||||
return res.sendStatus(401);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
} catch (err) {
|
|
||||||
next(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
required(req, res, next) {
|
|
||||||
if (!req.authInfo) {
|
|
||||||
return res.sendStatus(403);
|
|
||||||
} else {
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
optional(req, res, next) {
|
|
||||||
return next();
|
|
||||||
},
|
|
||||||
getUserIdMiddleware,
|
|
||||||
loadUserMiddleware,
|
|
||||||
};
|
|
||||||
|
|
Loading…
Reference in a new issue