1
0
mirror of https://github.com/bpatrik/pigallery2.git synced 2024-11-24 08:42:24 +02:00

improving authentication handling

implementing remember me
This commit is contained in:
Braun Patrik 2017-07-16 10:59:28 +02:00
parent f82c7d4169
commit a5e5f90ba6
13 changed files with 80 additions and 36 deletions

View File

@ -12,6 +12,7 @@ declare module Express {
export interface Session {
user?;
rememberMe?: boolean;
}
}

View File

@ -5,6 +5,7 @@ import {UserDTO, UserRoles} from "../../../common/entities/UserDTO";
import {ObjectManagerRepository} from "../../model/ObjectManagerRepository";
import {Config} from "../../../common/config/private/Config";
import {PasswordHelper} from "../../model/PasswordHelper";
import {Utils} from "../../../common/Utils";
export class AuthenticationMWs {
@ -69,6 +70,11 @@ export class AuthenticationMWs {
if (typeof req.session.user === 'undefined') {
return next(new ErrorDTO(ErrorCodes.NOT_AUTHENTICATED));
}
if (req.session.rememberMe === true) {
req.sessionOptions.expires = new Date(Date.now() + Config.Server.sessionTimeout);
} else {
delete(req.sessionOptions.expires);
}
return next();
}
@ -113,23 +119,29 @@ export class AuthenticationMWs {
//TODO: implement remember me
try {
//lets find the user
req.session.user = await ObjectManagerRepository.getInstance().UserManager.findOne({
const user = Utils.clone(await ObjectManagerRepository.getInstance().UserManager.findOne({
name: req.body.loginCredential.username,
password: req.body.loginCredential.password
});
}));
delete (user.password);
req.session.user = user;
if (req.body.loginCredential.rememberMe) {
req.sessionOptions.expires = new Date(Date.now() + Config.Server.sessionTimeout);
}
return next();
} catch (err) {
//if its a shared link, login as guest
try {
const user = await AuthenticationMWs.getSharingUser(req);
if (user) {
req.session.user = user;
return next();
}
} catch (err) {
return next(new ErrorDTO(ErrorCodes.CREDENTIAL_NOT_FOUND, null, err));
}
/* try {
const user = Utils.clone(await AuthenticationMWs.getSharingUser(req));
if (user) {
delete (user.password);
req.session.user = user;
return next();
}
} catch (err) {
return next(new ErrorDTO(ErrorCodes.CREDENTIAL_NOT_FOUND, null, err));
}*/
return next(new ErrorDTO(ErrorCodes.CREDENTIAL_NOT_FOUND));
}
@ -176,6 +188,7 @@ export class AuthenticationMWs {
public static logout(req: Request, res: Response, next: NextFunction) {
delete req.session.user;
delete req.session.rememberMe;
return next();
}

View File

@ -28,7 +28,6 @@ export class UserRouter {
private static addLogout(app) {
app.post("/api/user/logout",
AuthenticationMWs.authenticate,
AuthenticationMWs.logout,
RenderingMWs.renderOK
);

View File

@ -1,5 +1,5 @@
import * as _express from "express";
import * as _session from "express-session";
import * as _session from "cookie-session";
import * as _bodyParser from "body-parser";
import * as _http from "http";
import {PublicRouter} from "./routes/PublicRouter";
@ -47,15 +47,15 @@ export class Server {
/**
* Session above all
*/
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
this.app.use(_session({
name: "pigallery2-session",
secret: 'PiGallery2 secret',
cookie: {
maxAge: 60000 * 10,
httpOnly: false
},
resave: true,
saveUninitialized: false
keys: ["key1" + s4() + s4() + s4() + s4(), "key2" + s4() + s4() + s4() + s4(), "key3" + s4() + s4() + s4() + s4()]
}));
/**

View File

@ -37,6 +37,7 @@ export interface ServerConfig {
database: DataBaseConfig;
enableThreading: boolean;
sharing: SharingConfig;
sessionTimeout: number
}
export interface IPrivateConfig {
Server: ServerConfig;

View File

@ -16,6 +16,7 @@ export class PrivateConfigClass extends PublicConfigClass implements IPrivateCon
processingLibrary: ThumbnailProcessingLib.sharp,
qualityPriority: true
},
sessionTimeout: 1000 * 60 * 60 * 24 * 7,
database: {
type: DatabaseType.mysql,
mysql: {

View File

@ -115,14 +115,11 @@ export class GalleryComponent implements OnInit, OnDestroy {
};
private onRoute = async (params: Params) => {
console.log("onRoute", params);
const searchText = params['searchText'];
if (searchText && searchText != "") {
console.log("searching");
let typeString = params['type'];
if (typeString && typeString != "") {
console.log("with type");
let type: SearchTypes = <any>SearchTypes[typeString];
this._galleryService.search(searchText, type);
return;

View File

@ -46,6 +46,10 @@ export class GalleryService {
cw = await this.networkService.getJson<ContentWrapper>("/gallery/content/" + directoryName);
}
if (!cw) {
return;
}
this.galleryCacheService.setDirectory(cw.directory); //save it before adding references
if (this.lastRequest.directory != directoryName) {

View File

@ -1,4 +1,4 @@
import {Component, Input, OnChanges} from "@angular/core";
import {Component, ElementRef, Input, OnChanges} from "@angular/core";
import {GridPhoto} from "../../grid/GridPhoto";
@Component({
@ -15,7 +15,7 @@ export class GalleryLightboxPhotoComponent implements OnChanges {
imageLoaded: boolean = false;
constructor() {
constructor(public elementRef: ElementRef) {
}
ngOnChanges() {

View File

@ -30,11 +30,11 @@ export class LoginComponent implements OnInit {
this.loginError = null;
try {
console.log(await this._authService.login(this.loginCredential));
await this._authService.login(this.loginCredential);
} catch (error) {
console.log(error);
if (error && error.code === ErrorCodes.CREDENTIAL_NOT_FOUND) {
this.loginError = "Wrong username or password";
return;
}
}
}

View File

@ -5,6 +5,8 @@ import {UserService} from "./user.service";
import {LoginCredential} from "../../../../common/entities/LoginCredential";
import {Cookie} from "ng2-cookies";
import {Config} from "../../../../common/config/public/Config";
import {NetworkService} from "./network.service";
import {ErrorCodes, ErrorDTO} from "../../../../common/entities/Error";
declare module ServerInject {
export let user: UserDTO;
@ -15,7 +17,8 @@ export class AuthenticationService {
public user: BehaviorSubject<UserDTO>;
constructor(private _userService: UserService) {
constructor(private _userService: UserService,
private _networkService: NetworkService) {
this.user = new BehaviorSubject(null);
//picking up session..
@ -26,10 +29,22 @@ export class AuthenticationService {
this.getSessionUser();
} else {
if (Config.Client.authenticationRequired === false) {
this.user.next(<UserDTO>{name: "", password: "", role: UserRoles.Admin});
this.user.next(<UserDTO>{name: "", role: UserRoles.Admin});
}
}
_networkService.addGlobalErrorHandler((error: ErrorDTO) => {
if (error.code == ErrorCodes.NOT_AUTHENTICATED) {
this.user.next(null);
return true;
}
if (error.code == ErrorCodes.NOT_AUTHORISED) {
this.logout();
return true;
}
return false;
});
}
private async getSessionUser(): Promise<void> {

View File

@ -3,16 +3,19 @@ import {Headers, Http, RequestOptions} from "@angular/http";
import {Message} from "../../../../common/entities/Message";
import {SlimLoadingBarService} from "ng2-slim-loading-bar";
import "rxjs/Rx";
import {ErrorCodes} from "../../../../common/entities/Error";
import {ErrorCodes, ErrorDTO} from "../../../../common/entities/Error";
@Injectable()
export class NetworkService {
_baseUrl = "/api";
private globalErrorHandlers: Array<(error: ErrorDTO) => boolean> = [];
constructor(protected _http: Http, private slimLoadingBarService: SlimLoadingBarService) {
constructor(protected _http: Http,
private slimLoadingBarService: SlimLoadingBarService) {
}
private callJson<T>(method: string, url: string, data: any = {}): Promise<T> {
let body = JSON.stringify(data);
let headers = new Headers({'Content-Type': 'application/json'});
@ -37,7 +40,7 @@ export class NetworkService {
const err = (err) => {
this.slimLoadingBarService.complete();
return NetworkService.handleError(err);
return this.handleError(err);
};
if (method == "get" || method == "delete") {
@ -69,8 +72,13 @@ export class NetworkService {
return this.callJson("delete", url);
}
private static handleError(error: any) {
if (error.code) {
private handleError(error: any) {
if (typeof error.code !== "undefined") {
for (let i = 0; i < this.globalErrorHandlers.length; i++) {
if (this.globalErrorHandlers[i](error) == true) {
return;
}
}
return Promise.reject(error);
}
// TODO: in a real world app do something better
@ -78,4 +86,9 @@ export class NetworkService {
console.error(error);
return Promise.reject(error.message || error || 'Server error');
}
addGlobalErrorHandler(fn: (error: ErrorDTO) => boolean) {
this.globalErrorHandlers.push(fn);
}
}

View File

@ -27,10 +27,10 @@
"dependencies": {
"bcryptjs": "2.4.3",
"body-parser": "1.17.2",
"cookie-session": "^2.0.0-beta.2",
"ejs": "2.5.6",
"exif-parser": "0.1.9",
"express": "4.15.3",
"express-session": "1.15.3",
"flat-file-db": "1.0.0",
"jimp": "0.2.28",
"mysql": "2.13.0",
@ -56,8 +56,8 @@
"@angular/router": "~4.3.0",
"@types/bcryptjs": "^2.4.0",
"@types/chai": "^4.0.1",
"@types/cookie-session": "^2.0.32",
"@types/express": "^4.0.36",
"@types/express-session": "1.15.1",
"@types/gm": "^1.17.31",
"@types/jasmine": "^2.5.53",
"@types/jimp": "^0.2.1",