add response interceptors for refreshTokens method
This commit is contained in:
committed by
Daniel Hutzel
parent
76cbf7f9ca
commit
938abb6387
@@ -2,28 +2,26 @@ const cds = require("@sap/cds");
|
||||
const jwt = require("jsonwebtoken");
|
||||
|
||||
const { ACCESS_TOKEN_SECRET } = cds.env;
|
||||
|
||||
class MyUser extends cds.User {
|
||||
constructor(attr, roles, id) {
|
||||
super({ attr, _roles: [...roles, "authenticated-user"], id });
|
||||
super({ attr, _roles: [...roles], id });
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = (req, res, next) => {
|
||||
const { authorization: authHeader } = req.headers;
|
||||
const token = authHeader && authHeader.split(" ")[1];
|
||||
if (token === null) {
|
||||
return res.sendStatus(401);
|
||||
}
|
||||
|
||||
try {
|
||||
const decodedUser = jwt.verify(token, ACCESS_TOKEN_SECRET);
|
||||
req.user = new MyUser(
|
||||
{ ID: decodedUser.ID },
|
||||
decodedUser.roles,
|
||||
[decodedUser.roles, "authenticated-user"],
|
||||
decodedUser.email
|
||||
);
|
||||
} catch (error) {
|
||||
req.user = new MyUser({}, ["anonymous"], "");
|
||||
req.user = new cds.User();
|
||||
} finally {
|
||||
next();
|
||||
}
|
||||
|
||||
@@ -31,18 +31,29 @@ module.exports = async function () {
|
||||
const utcNowDateTime = moment().utc().format(UTC_DATE_TIME_FORMAT);
|
||||
|
||||
const transaction = await db.tx(req);
|
||||
|
||||
let { ID: lastInvoiceId } = await transaction.run(
|
||||
SELECT.one(Invoices).columns("ID").orderBy({ ID: "desc" })
|
||||
);
|
||||
|
||||
let { ID: lastInvoiceItemId } = await transaction.run(
|
||||
SELECT.one(InvoiceItems).columns("ID").orderBy({ ID: "desc" })
|
||||
);
|
||||
|
||||
const {
|
||||
results: [{ lastID: invoiceID }],
|
||||
} = await transaction.run(
|
||||
INSERT.into(Invoices)
|
||||
.columns("customer_ID", "total", "invoiceDate")
|
||||
.values(customerId, total, utcNowDateTime)
|
||||
.columns("ID", "customer_ID", "total", "invoiceDate")
|
||||
.values(++lastInvoiceId, customerId, total, utcNowDateTime)
|
||||
);
|
||||
|
||||
await transaction.run(
|
||||
INSERT.into(InvoiceItems)
|
||||
.columns("invoice_ID", "track_ID", "unitPrice")
|
||||
.columns("ID", "invoice_ID", "track_ID", "unitPrice")
|
||||
.rows(
|
||||
tracks.map(({ ID: trackID, unitPrice }) => [
|
||||
tracks.map(({ ID: trackID, unitPrice }, index) => [
|
||||
lastInvoiceItemId + index + 1,
|
||||
invoiceID,
|
||||
trackID,
|
||||
unitPrice,
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
using {sap.capire.media.store as my} from '../db/schema';
|
||||
|
||||
service ManageStore @(requires : 'employee') {
|
||||
entity Tracks as projection on my.Tracks;
|
||||
entity Albums as projection on my.Albums;
|
||||
entity Artists as projection on my.Artists;
|
||||
entity Tracks as projection on my.Tracks;
|
||||
entity Albums as projection on my.Albums;
|
||||
entity Artists as projection on my.Artists;
|
||||
/**
|
||||
* Below entities exposed due to errors when creating
|
||||
* Tracks/Albums/Artists
|
||||
*/
|
||||
entity MediaTypes as projection on my.MediaTypes;
|
||||
entity Genres as projection on my.Genres;
|
||||
entity Genres as projection on my.Genres;
|
||||
}
|
||||
|
||||
@@ -15,11 +15,22 @@ service Users {
|
||||
supportRep
|
||||
};
|
||||
|
||||
action login(email : String(111), password : String(200)) returns {
|
||||
roles : array of String(111);
|
||||
token : String(500);
|
||||
email : String(500);
|
||||
ID : Integer;
|
||||
type AuthData {
|
||||
accessToken : String(500);
|
||||
refreshToken : String(500);
|
||||
ID : Integer;
|
||||
email : String(500);
|
||||
roles : array of String(111);
|
||||
};
|
||||
|
||||
action login(email : String(111), password : String(200)) returns AuthData;
|
||||
|
||||
action refreshTokens(refreshToken : String(500)) returns {
|
||||
accessToken : String(500);
|
||||
refreshToken : String(500);
|
||||
ID : Integer;
|
||||
email : String(500);
|
||||
roles : array of String(111);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,9 @@ const cds = require("@sap/cds");
|
||||
const jwt = require("jsonwebtoken");
|
||||
const bcrypt = require("bcryptjs");
|
||||
|
||||
const { ACCESS_TOKEN_SECRET } = cds.env;
|
||||
const { ACCESS_TOKEN_SECRET, REFRESH_TOKEN_SECRET } = cds.env;
|
||||
const ACCESS_TOKEN_EXP_IN = "10m";
|
||||
const REFRESH_TOKEN_EXPIRES_IN = "20m";
|
||||
|
||||
const comparePasswords = async (password, hashedPassword) => {
|
||||
return new Promise((resolve, reject) =>
|
||||
@@ -17,10 +18,30 @@ const comparePasswords = async (password, hashedPassword) => {
|
||||
);
|
||||
};
|
||||
|
||||
const createTokens = (email, ID, roles) => {
|
||||
const accessToken = jwt.sign({ email, ID, roles }, ACCESS_TOKEN_SECRET, {
|
||||
expiresIn: ACCESS_TOKEN_EXP_IN,
|
||||
});
|
||||
const refreshToken = jwt.sign({ email, ID, roles }, REFRESH_TOKEN_SECRET, {
|
||||
expiresIn: REFRESH_TOKEN_EXPIRES_IN,
|
||||
});
|
||||
return [accessToken, refreshToken];
|
||||
};
|
||||
|
||||
module.exports = async function () {
|
||||
const db = await cds.connect.to("db");
|
||||
const { Employees, Customers } = db.entities;
|
||||
|
||||
async function getUser(email) {
|
||||
let userFromDb = await db.run(SELECT.one(Employees).where({ email }));
|
||||
let roles = ["employee"];
|
||||
if (!userFromDb) {
|
||||
userFromDb = await db.run(SELECT.one(Customers).where({ email }));
|
||||
roles = ["customer"];
|
||||
}
|
||||
return Object.assign({}, userFromDb, { roles });
|
||||
}
|
||||
|
||||
this.before("UPDATE", "*", async (req) => {
|
||||
req.query = req.query.where({ ID: req.user.attr.ID });
|
||||
});
|
||||
@@ -32,35 +53,58 @@ module.exports = async function () {
|
||||
this.on("login", async (req) => {
|
||||
const { email, password } = req.data;
|
||||
|
||||
let userFromDb = await db.run(SELECT.one(Employees).where({ email }));
|
||||
let roles = ["employee"];
|
||||
if (!userFromDb) {
|
||||
userFromDb = await db.run(SELECT.one(Customers).where({ email }));
|
||||
roles = ["customer"];
|
||||
}
|
||||
|
||||
const userFromDb = await getUser(email);
|
||||
if (!userFromDb) {
|
||||
req.reject(401);
|
||||
}
|
||||
|
||||
try {
|
||||
await comparePasswords(password, userFromDb.password);
|
||||
} catch (error) {
|
||||
req.reject(401);
|
||||
}
|
||||
|
||||
const token = jwt.sign(
|
||||
{ email, ID: userFromDb.ID, roles },
|
||||
ACCESS_TOKEN_SECRET,
|
||||
{
|
||||
expiresIn: ACCESS_TOKEN_EXP_IN,
|
||||
}
|
||||
const [accessToken, refreshToken] = createTokens(
|
||||
userFromDb.email,
|
||||
userFromDb.ID,
|
||||
userFromDb.roles
|
||||
);
|
||||
|
||||
return {
|
||||
token,
|
||||
roles,
|
||||
email: userFromDb.email,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
ID: userFromDb.ID,
|
||||
email: userFromDb.email,
|
||||
roles: userFromDb.roles,
|
||||
};
|
||||
});
|
||||
|
||||
this.on("refreshTokens", async (req) => {
|
||||
let decodedUser;
|
||||
try {
|
||||
const { refreshToken } = req.data;
|
||||
decodedUser = jwt.verify(refreshToken, REFRESH_TOKEN_SECRET);
|
||||
} catch (error) {
|
||||
req.reject(401);
|
||||
}
|
||||
|
||||
const userFromDb = await getUser(decodedUser.email);
|
||||
if (!userFromDb) {
|
||||
req.reject(401);
|
||||
}
|
||||
|
||||
const [accessToken, refreshToken] = createTokens(
|
||||
userFromDb.email,
|
||||
userFromDb.ID,
|
||||
userFromDb.roles
|
||||
);
|
||||
|
||||
return {
|
||||
accessToken,
|
||||
refreshToken,
|
||||
ID: userFromDb.ID,
|
||||
email: userFromDb.email,
|
||||
roles: userFromDb.roles,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user