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:
parent
f82c7d4169
commit
a5e5f90ba6
@ -12,6 +12,7 @@ declare module Express {
|
||||
|
||||
export interface Session {
|
||||
user?;
|
||||
rememberMe?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,6 @@ export class UserRouter {
|
||||
|
||||
private static addLogout(app) {
|
||||
app.post("/api/user/logout",
|
||||
AuthenticationMWs.authenticate,
|
||||
AuthenticationMWs.logout,
|
||||
RenderingMWs.renderOK
|
||||
);
|
||||
|
@ -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()]
|
||||
}));
|
||||
|
||||
/**
|
||||
|
@ -37,6 +37,7 @@ export interface ServerConfig {
|
||||
database: DataBaseConfig;
|
||||
enableThreading: boolean;
|
||||
sharing: SharingConfig;
|
||||
sessionTimeout: number
|
||||
}
|
||||
export interface IPrivateConfig {
|
||||
Server: ServerConfig;
|
||||
|
@ -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: {
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user