Commit 23e076c8 by Ooh-Ao

menu

parent 63435617
......@@ -17,12 +17,14 @@ import { LoginModel } from '../../shared/user-auth.model';
import { HttpClientModule } from '@angular/common/http';
import { Validators } from 'ngx-editor';
import { EmployeeService } from '../../portal-manage/services/employee.service';
import { EmployeeAuthService } from '../../portal-manage/services/employee-auth.service';
import { JwtService } from '../../portal-manage/services/jwt.service';
@Component({
selector: 'app-login',
standalone: true,
imports: [SharedModule, CarouselModule, CommonModule, RouterModule, FormsModule, HttpClientModule, ReactiveFormsModule],
providers: [AuthService, { provide: ToastrService, useClass: ToastrService }],
providers: [AuthService, EmployeeAuthService, JwtService, { provide: ToastrService, useClass: ToastrService }],
templateUrl: './login.component.html',
styleUrl: './login.component.scss'
})
......@@ -43,7 +45,9 @@ export class LoginComponent {
private routes: Router,
private formBuilder: FormBuilder,
public authService: AuthService,
private empServie: EmployeeService
private empServie: EmployeeService,
private employeeAuthService: EmployeeAuthService,
private jwtService: JwtService
) {
localStorage.clear()
}
......@@ -135,22 +139,111 @@ export class LoginComponent {
let loginCredentials: LoginModel = new LoginModel();
loginCredentials.username = this.loginForm.controls['username'].value;
loginCredentials.password = this.loginForm.controls['password'].value;
this.authService.login(loginCredentials).subscribe({
next: (response) => {
console.log('Login successful', response);
// Assuming your API returns a token, store it
// บันทึก token ใน TokenService
if (response.accessToken) {
this.tokenService.saveToken(response.accessToken);
}
// ตรวจสอบว่าเป็น JWT token หรือไม่
if (response.accessToken && this.isJwtToken(response.accessToken)) {
console.log('JWT token detected, processing...');
this.processJwtToken(response.accessToken);
} else {
console.log('Regular token, using traditional auth...');
this.processRegularToken(response);
}
this.routes.navigate(['/home']);
},
error: (error) => {
console.error('Login failed', error);
// Handle login error, e.g., display an error message to the user
this.showLoader = false;
this.error = 'Username หรือ Password ไม่ถูกต้อง';
}
});
}
/**
* ตรวจสอบว่าเป็น JWT token หรือไม่
*/
private isJwtToken(token: string): boolean {
try {
const parts = token.split('.');
return parts.length === 3;
} catch {
return false;
}
}
/**
* ประมวลผล JWT token
*/
private processJwtToken(jwtToken: string): void {
try {
// ตรวจสอบความถูกต้องของ JWT token
const decoded = this.jwtService.decodeToken(jwtToken);
if (decoded.isValid && !decoded.isExpired && decoded.payload) {
console.log('JWT token is valid:', decoded.payload);
// บันทึก JWT token ใน localStorage
localStorage.setItem('jwtToken', jwtToken);
// Authenticate ด้วย JWT
this.employeeAuthService.authenticateByJwtToken(jwtToken).subscribe(jwtEmployee => {
if (jwtEmployee) {
console.log('JWT Employee authenticated successfully:', jwtEmployee);
this.showLoader = false;
} else {
console.error('JWT authentication failed');
this.showLoader = false;
this.error = 'การยืนยันตัวตนล้มเหลว';
}
});
} else {
console.error('Invalid or expired JWT token:', decoded.error);
this.showLoader = false;
this.error = 'Token ไม่ถูกต้องหรือหมดอายุ';
}
} catch (error) {
console.error('JWT processing error:', error);
this.showLoader = false;
this.error = 'เกิดข้อผิดพลาดในการประมวลผล Token';
}
}
/**
* ประมวลผล regular token
*/
private processRegularToken(response: any): void {
try {
// ใช้ traditional authentication
if (response.userId || response.employeeId) {
const employeeId = response.employeeId || response.userId;
this.employeeAuthService.authenticateByEmployeeId(employeeId).subscribe(employee => {
if (employee) {
console.log('Employee authenticated successfully:', employee);
this.showLoader = false;
} else {
console.log('Employee not found, using default authentication');
this.showLoader = false;
}
});
} else {
console.log('No employee ID found, using default authentication');
this.showLoader = false;
}
} catch (error) {
console.error('Regular token processing error:', error);
this.showLoader = false;
}
}
// adminCompanyList(memberId: string) {
// this.empServie.getCompanyAdmin(memberId).subscribe(result => {
// if (result.length > 0) {
......
......@@ -61,6 +61,7 @@
<div class="font-bold text-gray-800 text-lg">{{ userInfo.fullName }}</div>
<div class="text-sm text-gray-600">{{ userInfo.department }}</div>
<div class="text-xs text-gray-500">{{ userInfo.position }}</div>
<div class="text-xs text-blue-600 font-medium">รหัส: {{ userInfo.employeeId }}</div>
</div>
</div>
<button
......
export interface JwtTokenPayload {
schema: string;
encode: string;
sub: string;
companyName: string;
dbName: string;
roles: string[];
workarea: string;
iss: string;
zmlogin: string;
role_level: string;
employeeid: string;
branch: string;
emp_position: string;
user_role: string;
uid: string;
companyid: string;
actorid: string;
lang: string;
ad: string;
firstlogin: string;
url_myhr: string;
app_name: string;
regionallty: string;
token_zeeme: string;
user_level: string;
fullname: string;
comid: string;
job: string;
user: string;
zm_user: string;
username: string;
memberid: string;
}
export interface JwtTokenHeader {
alg: string;
typ: string;
}
export interface JwtToken {
header: JwtTokenHeader;
payload: JwtTokenPayload;
signature: string;
}
export interface DecodedJwtToken {
isValid: boolean;
isExpired: boolean;
payload: JwtTokenPayload | null;
error?: string;
}
export interface EmployeeFromJwt {
employeeId: string;
fullName: string;
username: string;
email: string;
position: string;
job: string;
department: string;
companyName: string;
companyId: string;
branch: string;
workarea: string;
userLevel: string;
roles: string[];
language: string;
isFirstLogin: boolean;
isAdUser: boolean;
urlMyhr: string;
appName: string;
regionallty: string;
tokenZeeme: string;
zmUser: string;
memberId: string;
}
import { Injectable } from '@angular/core';
import { JwtTokenPayload, DecodedJwtToken, EmployeeFromJwt } from '../models/jwt-token.model';
@Injectable({
providedIn: 'root'
})
export class JwtService {
constructor() { }
/**
* Decode JWT token โดยไม่ต้องใช้ library ภายนอก
*/
decodeToken(token: string): DecodedJwtToken {
try {
if (!token) {
return {
isValid: false,
isExpired: false,
payload: null,
error: 'Token is empty'
};
}
// แยก JWT token เป็น 3 ส่วน
const parts = token.split('.');
if (parts.length !== 3) {
return {
isValid: false,
isExpired: false,
payload: null,
error: 'Invalid token format'
};
}
// Decode header
const header = this.base64UrlDecode(parts[0]);
const decodedHeader = JSON.parse(header);
// Decode payload
const payload = this.base64UrlDecode(parts[1]);
const decodedPayload: JwtTokenPayload = JSON.parse(payload);
// ตรวจสอบว่า token หมดอายุหรือไม่
const isExpired = this.isTokenExpired(decodedPayload);
return {
isValid: true,
isExpired: isExpired,
payload: decodedPayload,
error: isExpired ? 'Token expired' : undefined
};
} catch (error) {
return {
isValid: false,
isExpired: false,
payload: null,
error: `Token decode error: ${error}`
};
}
}
/**
* Decode base64url string
*/
private base64UrlDecode(str: string): string {
// แปลง base64url เป็น base64
let base64 = str.replace(/-/g, '+').replace(/_/g, '/');
// เพิ่ม padding ถ้าจำเป็น
while (base64.length % 4) {
base64 += '=';
}
// Decode base64
return decodeURIComponent(
atob(base64)
.split('')
.map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
.join('')
);
}
/**
* ตรวจสอบว่า token หมดอายุหรือไม่
*/
private isTokenExpired(payload: JwtTokenPayload): boolean {
// ตรวจสอบ exp claim ถ้ามี
if ('exp' in payload) {
const exp = (payload as any).exp;
if (exp) {
const currentTime = Math.floor(Date.now() / 1000);
return exp < currentTime;
}
}
// ตรวจสอบ iat claim ถ้ามี
if ('iat' in payload) {
const iat = (payload as any).iat;
if (iat) {
const currentTime = Math.floor(Date.now() / 1000);
// ถ้า token อายุเกิน 24 ชั่วโมงให้ถือว่า expired
const maxAge = 24 * 60 * 60; // 24 hours
return (currentTime - iat) > maxAge;
}
}
return false;
}
/**
* แปลง JWT payload เป็น Employee object
*/
convertToEmployee(payload: JwtTokenPayload): EmployeeFromJwt {
return {
employeeId: payload.employeeid || payload.uid || '',
fullName: payload.fullname || '',
username: payload.username || payload.user || '',
email: `${payload.username || payload.user || ''}@${payload.companyName || 'company.com'}`,
position: payload.emp_position || '',
job: payload.job || '',
department: this.extractDepartmentFromPosition(payload.emp_position || ''),
companyName: payload.companyName || '',
companyId: payload.companyid || '',
branch: payload.branch || '',
workarea: payload.workarea || '',
userLevel: payload.user_level || '',
roles: payload.roles || [],
language: payload.lang || 'tha',
isFirstLogin: payload.firstlogin === 'true',
isAdUser: payload.ad === 'true',
urlMyhr: payload.url_myhr || '',
appName: payload.app_name || '',
regionallty: payload.regionallty || '',
tokenZeeme: payload.token_zeeme || '',
zmUser: payload.zm_user || '',
memberId: payload.memberid || ''
};
}
/**
* แยกชื่อแผนกจากตำแหน่ง
*/
private extractDepartmentFromPosition(position: string): string {
if (!position) return '';
// ตัวอย่าง: P-RD-2201 -> RD (Research & Development)
const parts = position.split('-');
if (parts.length >= 2) {
const deptCode = parts[1];
const deptMap: { [key: string]: string } = {
'RD': 'ฝ่ายวิจัยและพัฒนา',
'IT': 'ฝ่ายเทคโนโลยีสารสนเทศ',
'HR': 'ฝ่ายทรัพยากรบุคคล',
'EX': 'ฝ่ายบริหาร',
'AC': 'ฝ่ายบัญชี',
'MK': 'ฝ่ายการตลาด',
'SL': 'ฝ่ายขาย',
'OP': 'ฝ่ายปฏิบัติการ'
};
return deptMap[deptCode] || deptCode;
}
return position;
}
/**
* ตรวจสอบว่า token ถูกต้องและไม่หมดอายุ
*/
isTokenValid(token: string): boolean {
const decoded = this.decodeToken(token);
return decoded.isValid && !decoded.isExpired;
}
/**
* ดึงข้อมูลพนักงานจาก token
*/
getEmployeeFromToken(token: string): EmployeeFromJwt | null {
const decoded = this.decodeToken(token);
if (decoded.isValid && !decoded.isExpired && decoded.payload) {
return this.convertToEmployee(decoded.payload);
}
return null;
}
/**
* ตรวจสอบสิทธิ์จาก roles ใน token
*/
hasRole(token: string, role: string): boolean {
const decoded = this.decodeToken(token);
if (decoded.isValid && decoded.payload) {
return decoded.payload.roles.includes(role);
}
return false;
}
/**
* ตรวจสอบ user level
*/
getUserLevel(token: string): string {
const decoded = this.decodeToken(token);
if (decoded.isValid && decoded.payload) {
return decoded.payload.user_level || '';
}
return '';
}
/**
* ตรวจสอบว่าเป็น admin หรือไม่
*/
isAdmin(token: string): boolean {
const userLevel = this.getUserLevel(token);
return userLevel.includes('Admin') || userLevel.includes('Manager') || userLevel.includes('Executive');
}
/**
* ตรวจสอบว่าเป็น employee หรือไม่
*/
isEmployee(token: string): boolean {
const userLevel = this.getUserLevel(token);
return userLevel.includes('Emp-User') || userLevel.includes('Employee');
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment