import { Injectable } from '@angular/core';
import { environment } from '../../environments/environment'
import { SHA3, PBKDF2, AES, enc, mode, pad } from 'crypto-js'
import { random } from 'crypto-js/lib-typedarrays'
@Injectable({
providedIn: 'root'
})
export class AuthService {
// 登入狀態
private _loginUserId: string = '';
private _loginUserName: string = '來賓';
private _status: AuthStatus = AuthStatus.Guest;
private _authToken?: string = undefined;
private _expiredTime?: Date = undefined;
...略...
/**
* 把登入狀態加密並存入 localStorage。
*/
private doStoreAuthState2(): void {
debugger;
const authState = {
loginUserId: this._loginUserId,
loginUserName: this._loginUserName,
status: this._status,
authToken: this._authToken,
expiredTime: this._expiredTime,
}
const authJson = JSON.stringify(authState);
// meta
const iterations = 10000;
const salt = 'this-is-the-salt';
const iv = random(128 / 8).toString(enc.Hex);
// 加密
const key = PBKDF2(environment.authSeed, salt, { keySize: 256 / 32, iterations });
const cyphertext = AES.encrypt(authJson, key, {
mode: mode.CBC,
padding: pad.Pkcs7,
iv: enc.Hex.parse(iv)
}).toString();
const hash = SHA3(cyphertext, { outputLength: 384 }).toString();
// 保存
localStorage.setItem(environment.authStateRepo, hash + '.' + cyphertext + '.' + iv);
}
/**
* 自 localStorage 還原登入狀態。
*/
private doRestoreAuthState2(): void {
const authCypher = localStorage.getItem(environment.authStateRepo);
if (!authCypher) {
localStorage.removeItem(environment.authStateRepo); // 移除無效登入資訊
return;
}
const [hash, cyphertext, iv] = authCypher.split('.');
// check hash
const hash2 = SHA3(cyphertext, { outputLength: 384 }).toString();
if (hash !== hash2) {
localStorage.removeItem(environment.authStateRepo); // 移除無效登入資訊
return;
}
// 解密
const iterations = 10000;
const salt = 'this-is-the-salt';
const key2 = PBKDF2(environment.authSeed, salt, { keySize: 256 / 32, iterations });
const decryptedBlob = AES.decrypt(cyphertext, key2, {
mode: mode.CBC,
padding: pad.Pkcs7,
iv: enc.Hex.parse(iv)
})
const authJson = enc.Utf8.stringify(decryptedBlob)
const authState = JSON.parse(authJson);
// 檢查時效仍有效否
if (authState.status !== AuthStatus.Authed) {
localStorage.removeItem(environment.authStateRepo); // 移除無效登入資訊
return;
}
if (new Date(authState.expiredTime) <= new Date()) {
localStorage.removeItem(environment.authStateRepo); // 移除無效登入資訊
return;
}
console.debug('AuthService.restoreAuthState2.SUCCESS', authState)
// 以上步驟全部成功的話
// setup auth status
this._loginUserId = authState.loginUserId;
this._loginUserName = authState.loginUserName;
this._authToken = authState.authToken;
this._expiredTime = authState.expiredTime;
this._status = authState.status; // 狀態最後填入
}
}