diff --git a/client/app/app.component.html b/client/app/app.component.html
index 049a7757..eecc43d7 100644
--- a/client/app/app.component.html
+++ b/client/app/app.component.html
@@ -5,22 +5,22 @@
Home
-
+
Cats
-
+
Login
-
+
Register
-
+
Account ({{auth.currentUser.username}})
-
+
Admin
-
+
Logout
diff --git a/client/app/app.module.ts b/client/app/app.module.ts
index a0ccfb9f..9384aa69 100644
--- a/client/app/app.module.ts
+++ b/client/app/app.module.ts
@@ -1,12 +1,10 @@
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { RoutingModule } from './routing.module';
+import { AuthModule } from './auth.module';
import { SharedModule } from './shared/shared.module';
import { CatService } from './services/cat.service';
import { UserService } from './services/user.service';
-import { AuthService } from './services/auth.service';
-import { AuthGuardLogin } from './services/auth-guard-login.service';
-import { AuthGuardAdmin } from './services/auth-guard-admin.service';
import { AppComponent } from './app.component';
import { CatsComponent } from './cats/cats.component';
import { AboutComponent } from './about/about.component';
@@ -30,13 +28,11 @@ import { NotFoundComponent } from './not-found/not-found.component';
NotFoundComponent
],
imports: [
+ AuthModule,
RoutingModule,
SharedModule
],
providers: [
- AuthService,
- AuthGuardLogin,
- AuthGuardAdmin,
CatService,
UserService
],
diff --git a/client/app/auth.module.ts b/client/app/auth.module.ts
new file mode 100644
index 00000000..c4cccfd2
--- /dev/null
+++ b/client/app/auth.module.ts
@@ -0,0 +1,30 @@
+import { NgModule } from '@angular/core';
+import { Http, RequestOptions } from '@angular/http';
+import { AuthHttp, AuthConfig } from 'angular2-jwt';
+
+import { AuthService } from './services/auth.service';
+import { AuthGuardLogin } from './services/auth-guard-login.service';
+import { AuthGuardAdmin } from './services/auth-guard-admin.service';
+
+export function authHttpServiceFactory(http: Http, options: RequestOptions) {
+ return new AuthHttp(new AuthConfig({
+ tokenName: 'token',
+ tokenGetter: (() => localStorage.getItem('token')),
+ globalHeaders: [{'Content-Type': 'application/json'}],
+ }), http, options);
+}
+
+@NgModule({
+ providers: [
+ AuthService,
+ AuthGuardLogin,
+ AuthGuardAdmin,
+ {
+ provide: AuthHttp,
+ useFactory: authHttpServiceFactory,
+ deps: [Http, RequestOptions]
+ }
+ ]
+})
+
+export class AuthModule { }
diff --git a/client/app/login/login.component.ts b/client/app/login/login.component.ts
index 414a270f..ef841fe5 100644
--- a/client/app/login/login.component.ts
+++ b/client/app/login/login.component.ts
@@ -28,7 +28,7 @@ export class LoginComponent implements OnInit {
public toast: ToastComponent) { }
ngOnInit() {
- if (this.auth.loggedIn) {
+ if (this.auth.loggedIn()) {
this.router.navigate(['/']);
}
this.loginForm = this.formBuilder.group({
diff --git a/client/app/services/auth-guard-login.service.ts b/client/app/services/auth-guard-login.service.ts
index e42e78e5..0cf05c4e 100644
--- a/client/app/services/auth-guard-login.service.ts
+++ b/client/app/services/auth-guard-login.service.ts
@@ -8,7 +8,11 @@ export class AuthGuardLogin implements CanActivate {
constructor(public auth: AuthService, private router: Router) {}
canActivate() {
- return this.auth.loggedIn;
+ if (this.auth.loggedIn()) {
+ return true;
+ } else {
+ return false;
+ }
}
}
diff --git a/client/app/services/auth.service.ts b/client/app/services/auth.service.ts
index c2a33a2f..28626ed6 100644
--- a/client/app/services/auth.service.ts
+++ b/client/app/services/auth.service.ts
@@ -1,12 +1,11 @@
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
-import { JwtHelper } from 'angular2-jwt';
+import { JwtHelper, tokenNotExpired } from 'angular2-jwt';
import { UserService } from '../services/user.service';
@Injectable()
export class AuthService {
- loggedIn = false;
isAdmin = false;
jwtHelper: JwtHelper = new JwtHelper();
@@ -28,14 +27,13 @@ export class AuthService {
localStorage.setItem('token', res.token);
const decodedUser = this.decodeUserFromToken(res.token);
this.setCurrentUser(decodedUser);
- return this.loggedIn;
+ return this.loggedIn();
}
);
}
logout() {
localStorage.removeItem('token');
- this.loggedIn = false;
this.isAdmin = false;
this.currentUser = { _id: '', username: '', role: '' };
this.router.navigate(['/']);
@@ -46,7 +44,6 @@ export class AuthService {
}
setCurrentUser(decodedUser) {
- this.loggedIn = true;
this.currentUser._id = decodedUser._id;
this.currentUser.username = decodedUser.username;
this.currentUser.role = decodedUser.role;
@@ -54,4 +51,8 @@ export class AuthService {
delete decodedUser.role;
}
+ loggedIn() {
+ return tokenNotExpired();
+ }
+
}
diff --git a/client/app/services/cat.service.ts b/client/app/services/cat.service.ts
index 0179611e..8263709a 100644
--- a/client/app/services/cat.service.ts
+++ b/client/app/services/cat.service.ts
@@ -1,5 +1,6 @@
import { Injectable } from '@angular/core';
import { Http, Headers, RequestOptions } from '@angular/http';
+import { AuthHttp } from 'angular2-jwt';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
@@ -7,33 +8,30 @@ import 'rxjs/add/operator/map';
@Injectable()
export class CatService {
- private headers = new Headers({ 'Content-Type': 'application/json', 'charset': 'UTF-8' });
- private options = new RequestOptions({ headers: this.headers });
-
- constructor(private http: Http) { }
+ constructor(public authHttp: AuthHttp) { }
getCats(): Observable {
- return this.http.get('/api/cats').map(res => res.json());
+ return this.authHttp.get('/api/cats').map(res => res.json());
}
countCats(): Observable {
- return this.http.get('/api/cats/count').map(res => res.json());
+ return this.authHttp.get('/api/cats/count').map(res => res.json());
}
addCat(cat): Observable {
- return this.http.post('/api/cat', JSON.stringify(cat), this.options);
+ return this.authHttp.post('/api/cat', JSON.stringify(cat));
}
getCat(cat): Observable {
- return this.http.get(`/api/cat/${cat._id}`).map(res => res.json());
+ return this.authHttp.get(`/api/cat/${cat._id}`).map(res => res.json());
}
editCat(cat): Observable {
- return this.http.put(`/api/cat/${cat._id}`, JSON.stringify(cat), this.options);
+ return this.authHttp.put(`/api/cat/${cat._id}`, JSON.stringify(cat));
}
deleteCat(cat): Observable {
- return this.http.delete(`/api/cat/${cat._id}`, this.options);
+ return this.authHttp.delete(`/api/cat/${cat._id}`);
}
}
diff --git a/client/app/services/user.service.ts b/client/app/services/user.service.ts
index e179c0b8..8de03239 100644
--- a/client/app/services/user.service.ts
+++ b/client/app/services/user.service.ts
@@ -1,5 +1,6 @@
import { Injectable } from '@angular/core';
import { Http, Headers, RequestOptions } from '@angular/http';
+import { AuthHttp } from 'angular2-jwt';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
@@ -10,7 +11,8 @@ export class UserService {
private headers = new Headers({ 'Content-Type': 'application/json', 'charset': 'UTF-8' });
private options = new RequestOptions({ headers: this.headers });
- constructor(private http: Http) { }
+ constructor(private http: Http,
+ public authHttp: AuthHttp) { }
register(user): Observable {
return this.http.post('/api/user', JSON.stringify(user), this.options);
@@ -21,27 +23,27 @@ export class UserService {
}
getUsers(): Observable {
- return this.http.get('/api/users').map(res => res.json());
+ return this.authHttp.get('/api/users').map(res => res.json());
}
countUsers(): Observable {
- return this.http.get('/api/users/count').map(res => res.json());
+ return this.authHttp.get('/api/users/count').map(res => res.json());
}
addUser(user): Observable {
- return this.http.post('/api/user', JSON.stringify(user), this.options);
+ return this.authHttp.post('/api/user', JSON.stringify(user));
}
getUser(user): Observable {
- return this.http.get(`/api/user/${user._id}`).map(res => res.json());
+ return this.authHttp.get(`/api/user/${user._id}`).map(res => res.json());
}
editUser(user): Observable {
- return this.http.put(`/api/user/${user._id}`, JSON.stringify(user), this.options);
+ return this.authHttp.put(`/api/user/${user._id}`, JSON.stringify(user));
}
deleteUser(user): Observable {
- return this.http.delete(`/api/user/${user._id}`, this.options);
+ return this.authHttp.delete(`/api/user/${user._id}`);
}
}
diff --git a/package.json b/package.json
index afa0d6ef..337a1fe1 100644
--- a/package.json
+++ b/package.json
@@ -39,6 +39,7 @@
"core-js": "^2.5.1",
"dotenv": "^4.0.0",
"express": "^4.16.2",
+ "express-jwt": "^5.3.0",
"font-awesome": "^4.7.0",
"jquery": "^3.2.1",
"jsonwebtoken": "^8.1.0",
diff --git a/server/controllers/base.ts b/server/controllers/base.ts
index 04d8656d..623be379 100644
--- a/server/controllers/base.ts
+++ b/server/controllers/base.ts
@@ -4,58 +4,95 @@ abstract class BaseCtrl {
// Get all
getAll = (req, res) => {
- this.model.find({}, (err, docs) => {
- if (err) { return console.error(err); }
- res.json(docs);
- });
- }
+ if (!req.payload.user._id) {
+ res.status(401).json({
+ 'message' : 'UnauthorizedError: private'
+ });
+ } else {
+ this.model.find({}, (err, items) => {
+ if (err) { return console.error(err); }
+ res.json(items);
+ });
+ }
+ };
// Count all
count = (req, res) => {
- this.model.count((err, count) => {
- if (err) { return console.error(err); }
- res.json(count);
- });
- }
+ if (!req.payload.user._id) {
+ res.status(401).json({
+ 'message' : 'UnauthorizedError: private'
+ });
+ } else {
+ this.model.count((err, count) => {
+ if (err) { return console.error(err); }
+ res.json(count);
+ });
+ }
+ };
// Insert
insert = (req, res) => {
- const obj = new this.model(req.body);
- obj.save((err, item) => {
- // 11000 is the code for duplicate key error
- if (err && err.code === 11000) {
- res.sendStatus(400);
- }
- if (err) {
- return console.error(err);
- }
- res.status(200).json(item);
- });
- }
+ if (!req.payload.user._id) {
+ res.status(401).json({
+ 'message' : 'UnauthorizedError: private'
+ });
+ } else {
+ const obj = new this.model(req.body);
+ obj.save((err, item) => {
+ // 11000 is the code for duplicate key error
+ if (err && err.code === 11000) {
+ res.sendStatus(400);
+ }
+ if (err) {
+ return console.error(err);
+ }
+ res.status(200).json(item);
+ });
+ }
+ };
// Get by id
get = (req, res) => {
- this.model.findOne({ _id: req.params.id }, (err, obj) => {
- if (err) { return console.error(err); }
- res.json(obj);
- });
- }
+ if (!req.payload.user._id) {
+ res.status(401).json({
+ 'message' : 'UnauthorizedError: private'
+ });
+ } else {
+ this.model.findOne({ _id: req.params.id }, (err, obj) => {
+ if (err) { return console.error(err); }
+ res.json(obj);
+ });
+ }
+ };
// Update by id
update = (req, res) => {
- this.model.findOneAndUpdate({ _id: req.params.id }, req.body, (err) => {
- if (err) { return console.error(err); }
- res.sendStatus(200);
- });
- }
+ if (!req.payload.user._id) {
+ res.status(401).json({
+ 'message' : 'UnauthorizedError: private'
+ });
+ } else {
+ this.model.findOneAndUpdate({ _id: req.params.id }, req.body, (err) => {
+ if (err) { return console.error(err); }
+ res.sendStatus(200);
+ });
+ }
+ };
// Delete by id
delete = (req, res) => {
- this.model.findOneAndRemove({ _id: req.params.id }, (err) => {
- if (err) { return console.error(err); }
- res.sendStatus(200);
- });
- }
+ if (!req.payload.user._id) {
+ res.status(401).json({
+ 'message' : 'UnauthorizedError: private'
+ });
+ } else {
+ this.model.findOneAndRemove({ _id: req.params.id }, (err) => {
+ if (err) { return console.error(err); }
+ res.sendStatus(200);
+ });
+ }
+ };
+
}
export default BaseCtrl;
diff --git a/server/controllers/user.ts b/server/controllers/user.ts
index 4bbc7574..21179c49 100644
--- a/server/controllers/user.ts
+++ b/server/controllers/user.ts
@@ -7,6 +7,20 @@ import BaseCtrl from './base';
export default class UserCtrl extends BaseCtrl {
model = User;
+ register = (req, res) => {
+ const obj = new this.model(req.body);
+ obj.save((err, item) => {
+ // 11000 is the code for duplicate key error
+ if (err && err.code === 11000) {
+ res.sendStatus(400);
+ }
+ if (err) {
+ return console.error(err);
+ }
+ res.status(200).json(item);
+ });
+ };
+
login = (req, res) => {
this.model.findOne({ email: req.body.email }, (err, user) => {
if (!user) { return res.sendStatus(403); }
diff --git a/server/routes.ts b/server/routes.ts
index 1ec8093e..4f0acc78 100644
--- a/server/routes.ts
+++ b/server/routes.ts
@@ -1,4 +1,6 @@
import * as express from 'express';
+import * as jwt from 'express-jwt';
+import * as dotenv from 'dotenv';
import CatCtrl from './controllers/cat';
import UserCtrl from './controllers/user';
@@ -8,26 +10,30 @@ import User from './models/user';
export default function setRoutes(app) {
const router = express.Router();
+ const auth = jwt({
+ secret: process.env.SECRET_TOKEN,
+ userProperty: 'payload'
+ });
const catCtrl = new CatCtrl();
const userCtrl = new UserCtrl();
// Cats
- router.route('/cats').get(catCtrl.getAll);
- router.route('/cats/count').get(catCtrl.count);
- router.route('/cat').post(catCtrl.insert);
- router.route('/cat/:id').get(catCtrl.get);
- router.route('/cat/:id').put(catCtrl.update);
- router.route('/cat/:id').delete(catCtrl.delete);
+ router.route('/cats').get(auth, catCtrl.getAll);
+ router.route('/cats/count').get(auth, catCtrl.count);
+ router.route('/cat').post(auth, catCtrl.insert);
+ router.route('/cat/:id').get(auth, catCtrl.get);
+ router.route('/cat/:id').put(auth, catCtrl.update);
+ router.route('/cat/:id').delete(auth, catCtrl.delete);
// Users
router.route('/login').post(userCtrl.login);
- router.route('/users').get(userCtrl.getAll);
- router.route('/users/count').get(userCtrl.count);
- router.route('/user').post(userCtrl.insert);
- router.route('/user/:id').get(userCtrl.get);
- router.route('/user/:id').put(userCtrl.update);
- router.route('/user/:id').delete(userCtrl.delete);
+ router.route('/users').get(auth, userCtrl.getAll);
+ router.route('/users/count').get(auth, userCtrl.count);
+ router.route('/user').post(userCtrl.register);
+ router.route('/user/:id').get(auth, userCtrl.get);
+ router.route('/user/:id').put(auth, userCtrl.update);
+ router.route('/user/:id').delete(auth, userCtrl.delete);
// Apply the routes to our application with the prefix /api
app.use('/api', router);