Implemented authorisation checks and logout

This commit is contained in:
Mark van Renswoude 2018-04-26 15:39:21 +02:00
parent 0e10f38383
commit 9defe0746f
9 changed files with 130 additions and 19 deletions

View File

@ -2,9 +2,10 @@ const config = require('../../config');
const express = require('Express'); const express = require('Express');
const asyncHandler = require('express-async-handler'); const asyncHandler = require('express-async-handler');
const jwt = require('jsonwebtoken'); const jwt = require('jsonwebtoken');
const AuthTokens = require('../authtokens');
async function checkAuthorization(req, res, onVerified) async function checkAuthorization(req, res, repository, onVerified)
{ {
if (!req.headers.authorization || req.headers.authorization.split(' ')[0] !== 'Bearer') if (!req.headers.authorization || req.headers.authorization.split(' ')[0] !== 'Bearer')
{ {
@ -24,7 +25,16 @@ async function checkAuthorization(req, res, onVerified)
} }
if (decoded.userId) if (decoded.userId)
await onVerified(decoded); {
var user = await repository.users.getUser(decoded.userId);
if (user === null || !user.active)
{
res.sendStatus(403);
return;
}
else
await onVerified(user);
}
else else
res.sendStatus(400); res.sendStatus(400);
} }
@ -42,12 +52,26 @@ module.exports = (repository) =>
{ {
var router = express.Router(); var router = express.Router();
router.get('/whoami', asyncHandler(async (req, res) =>
{
await checkAuthorization(req, res, repository, async (user) =>
{
res.send({
userId: user.userId,
username: user.username,
auth: user.auth
});
});
}));
router.get('/codes', asyncHandler(async (req, res) => router.get('/codes', asyncHandler(async (req, res) =>
{ {
await checkAuthorization(req, res, async (decoded) => await checkAuthorization(req, res, repository, async (user) =>
{ {
var codes = await repository.codes.getCodes(decoded.userId); var codes = await repository.codes.getCodes(user.hasAuth(AuthTokens.ViewAllCodes) ? null : user.userId);
var usernames = await repository.users.getUsernames(); var usernames = await repository.users.getUserNames();
codes.forEach((item) => codes.forEach((item) =>
{ {
@ -61,10 +85,10 @@ module.exports = (repository) =>
router.get('/uploads', asyncHandler(async (req, res) => router.get('/uploads', asyncHandler(async (req, res) =>
{ {
await checkAuthorization(req, res, async (decoded) => await checkAuthorization(req, res, repository, async (user) =>
{ {
var files = await repository.uploads.getUploads(decoded.userId); var files = await repository.uploads.getUploads(user.hasAuth(AuthTokens.ViewAllUploads) ? null : user.userId);
var usernames = await repository.users.getUsernames(); var usernames = await repository.users.getUserNames();
files.forEach((item) => files.forEach((item) =>
{ {

View File

@ -47,8 +47,7 @@ module.exports = (repository) =>
if (user !== null) if (user !== null)
{ {
jwt.sign({ jwt.sign({
userId: user.id, userId: user.id
auth: user.auth
}, config.jwtSecret, (err, token) => }, config.jwtSecret, (err, token) =>
{ {
if (err) if (err)

View File

@ -1,5 +1,7 @@
const AuthTokens = { const AuthTokens = {
ManageUsers: 'manageUsers' ManageUsers: 'manageUsers',
ViewAllUploads: 'viewAllUploads',
ViewAllCodes: 'viewAllCodes'
} }
var all = []; var all = [];

View File

@ -10,6 +10,7 @@ class User
self.id = values.id || values._id || null; self.id = values.id || values._id || null;
self.username = values.username || null; self.username = values.username || null;
self.name = values.name || null;
self.password = values.password || null; self.password = values.password || null;
self.email = values.email || null; self.email = values.email || null;
self.auth = values.auth || []; self.auth = values.auth || [];
@ -25,6 +26,8 @@ class User
hasAuth(token) hasAuth(token)
{ {
var self = this;
return self.auth.includes(token); return self.auth.includes(token);
} }
} }
@ -58,6 +61,7 @@ class UserRepository
{ {
self.addUser(new User({ self.addUser(new User({
username: 'admin', username: 'admin',
name: 'Administrator',
password: 'changeme', password: 'changeme',
auth: AuthTokens.all auth: AuthTokens.all
})) }))
@ -103,6 +107,32 @@ class UserRepository
} }
getUser(userId)
{
var self = this;
return new Promise((resolve, reject) =>
{
self.store.findOne({ _id: userId }, (err, doc) =>
{
if (err)
{
reject(err);
return;
}
if (doc == null)
{
resolve(false);
return;
}
resolve(new User(doc));
});
});
}
addUser(user) addUser(user)
{ {
var self = this; var self = this;
@ -119,6 +149,7 @@ class UserRepository
self.store.insert({ self.store.insert({
username: user.username, username: user.username,
name: user.name,
email: user.email, email: user.email,
hashedPassword: hash, hashedPassword: hash,
created: user.created, created: user.created,
@ -140,7 +171,7 @@ class UserRepository
} }
getUsernames() getUserNames()
{ {
var self = this; var self = this;
@ -154,13 +185,13 @@ class UserRepository
return; return;
} }
var usernames = {}; var userNames = {};
docs.forEach((dbUser) => docs.forEach((dbUser) =>
{ {
usernames[dbUser._id] = dbUser.username userNames[dbUser._id] = dbUser.name
}); });
resolve(usernames); resolve(userNames);
}); });
}); });
} }

View File

@ -24,6 +24,7 @@ export default {
admin: { admin: {
loading: 'Loading…', loading: 'Loading…',
empty: 'No data', empty: 'No data',
logout: 'Logout',
login: { login: {
usernamePlaceholder: 'Username or e-mail address', usernamePlaceholder: 'Username or e-mail address',

View File

@ -24,6 +24,7 @@ export default {
admin: { admin: {
loading: 'Bezig met laden…', loading: 'Bezig met laden…',
empty: 'Geen gegevens', empty: 'Geen gegevens',
logout: 'Uitloggen',
login: { login: {
usernamePlaceholder: 'Gebruikersnaam of e-mail adres', usernamePlaceholder: 'Gebruikersnaam of e-mail adres',

View File

@ -5,7 +5,11 @@
<ul class="pure-menu-list"> <ul class="pure-menu-list">
<menu-link route="/admin/uploads" :title="$t('admin.menu.uploads')"></menu-link> <menu-link route="/admin/uploads" :title="$t('admin.menu.uploads')"></menu-link>
<menu-link route="/admin/codes" :title="$t('admin.menu.codes')"></menu-link> <menu-link route="/admin/codes" :title="$t('admin.menu.codes')"></menu-link>
<menu-link route="/admin/users" :title="$t('admin.menu.users')"></menu-link> <menu-link route="/admin/users" :title="$t('admin.menu.users')" v-if="hasAuth('manageUsers')"></menu-link>
<li class="pure-menu-item right">
<a class="pure-menu-link" href="#" @click="logout">{{ $t('admin.logout') }}</a>
</li>
</ul> </ul>
</div> </div>
</div> </div>
@ -13,6 +17,8 @@
</template> </template>
<script> <script>
import shared from '../../shared';
var menuLink = { var menuLink = {
props: ['route', 'title'], props: ['route', 'title'],
template: '<router-link tag="li" :to="route" class="pure-menu-item" active-class="pure-menu-selected">' + template: '<router-link tag="li" :to="route" class="pure-menu-item" active-class="pure-menu-selected">' +
@ -30,6 +36,22 @@ export default {
components: { components: {
'menu-link': menuLink 'menu-link': menuLink
},
methods: {
hasAuth(token)
{
return shared.user.auth.indexOf(token) > -1;
},
logout()
{
var self = this;
shared.token = null;
self.$router.push('/admin');
}
} }
} }
</script> </script>
@ -47,6 +69,11 @@ export default {
background-color: black; background-color: black;
.pure-menu-horizontal .pure-menu-list
{
width: 100%;
}
.pure-menu-link .pure-menu-link
{ {
color: white; color: white;
@ -64,5 +91,10 @@ export default {
background-color: #228dd4; background-color: #228dd4;
} }
} }
.right
{
float: right;
}
} }
</style> </style>

View File

@ -92,7 +92,6 @@ export default {
if (parts.length > 0) if (parts.length > 0)
ext = parts.pop(); ext = parts.pop();
console.log(ext);
return '/images/fileicons/32px/' + ext + '.png'; return '/images/fileicons/32px/' + ext + '.png';
} }
} }

View File

@ -1,10 +1,13 @@
import Vue from 'vue'; import Vue from 'vue';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import axios from 'axios';
export default new Vue({ export default new Vue({
data() { data() {
return { return {
token: null token: null,
user: []
} }
}, },
@ -20,7 +23,26 @@ export default new Vue({
watch: { watch: {
token(newValue) token(newValue)
{ {
Cookies.set('token', newValue); var self = this;
if (newValue !== null)
{
Cookies.set('token', newValue);
axios.get('/admin/whoami', {
headers: {
Authorization: 'Bearer ' + self.token
}})
.then((response) =>
{
self.user = response.data;
});
}
else
{
Cookies.remove('token');
self.user = null;
}
} }
} }
}); });