Implemented authorisation checks and logout
This commit is contained in:
parent
0e10f38383
commit
9defe0746f
|
@ -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) =>
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
const AuthTokens = {
|
const AuthTokens = {
|
||||||
ManageUsers: 'manageUsers'
|
ManageUsers: 'manageUsers',
|
||||||
|
ViewAllUploads: 'viewAllUploads',
|
||||||
|
ViewAllCodes: 'viewAllCodes'
|
||||||
}
|
}
|
||||||
|
|
||||||
var all = [];
|
var all = [];
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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>
|
|
@ -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';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
Loading…
Reference in New Issue