Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mySkill-x
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
angular
mySkill-x
Commits
b75eec55
Commit
b75eec55
authored
Apr 17, 2025
by
Ooh-Ao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
tokenservice httpinceptor
parent
aff91f9f
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
126 additions
and
106 deletions
+126
-106
header.component.html
src/app/shared/components/header/header.component.html
+0
-0
auth.service.ts
src/app/shared/services/auth.service.ts
+10
-17
http-request.interceptor.ts
src/app/shared/services/http-request.interceptor.ts
+52
-63
token.service.ts
src/app/shared/services/token.service.ts
+63
-14
environment.ts
src/environments/environment.ts
+1
-12
No files found.
src/app/shared/components/header/header.component.html
View file @
b75eec55
This diff is collapsed.
Click to expand it.
src/app/shared/services/auth.service.ts
View file @
b75eec55
...
...
@@ -10,23 +10,15 @@ import { environment } from 'src/environments/environment';
})
export
class
AuthService
{
authState
:
any
;
api
=
"/auth"
urlApi
=
environment
.
baseUrl
+
this
.
api
apiBaseUrl
=
"/auth"
;
constructor
(
private
router
:
Router
,
private
http
:
HttpClient
)
{
constructor
(
private
router
:
Router
,
private
http
:
HttpClient
)
{
}
refreshToken
():
Observable
<
{
accessToken
:
string
;
refreshToken
:
string
}
>
{
return
this
.
http
.
post
<
{
accessToken
:
string
;
refreshToken
:
string
}
>
(
`
${
this
.
urlApi
}
/refresh-token`
,
{
refreshToken
:
sessionStorage
.
getItem
(
'refreshToken'
)
}
).
pipe
(
tap
(
response
=>
{
sessionStorage
.
setItem
(
'accessToken'
,
response
.
accessToken
);
sessionStorage
.
setItem
(
'refreshToken'
,
response
.
refreshToken
);
})
);
refreshToken
(
token
:
string
)
{
return
this
.
http
.
post
<
any
>
(
this
.
apiBaseUrl
+
"/refresh-token"
,
{
"refreshToken"
:
token
});
}
get
isUserAnonymousLoggedIn
():
boolean
{
...
...
@@ -53,14 +45,15 @@ export class AuthService {
}
}
loginWithUserPass
(
username
:
string
,
password
:
string
):
Observable
<
{
accessToken
:
string
,
refreshToken
:
string
}
>
{
loginWithUserPass
(
username
:
string
,
password
:
string
):
Observable
<
{
accessToken
:
string
,
refreshToken
:
string
}
>
{
const
body
=
{
username
:
username
,
password
:
password
}
return
this
.
http
.
post
<
{
accessToken
:
string
,
refreshToken
:
string
}
>
(
this
.
urlApi
+
"/login"
,
body
)
return
this
.
http
.
post
<
{
accessToken
:
string
,
refreshToken
:
string
}
>
(
this
.
apiBaseUrl
+
"/login"
,
body
)
}
logout
(){
logout
()
{
sessionStorage
.
clear
()
localStorage
.
clear
()
this
.
router
.
navigate
([
'/auth/login'
]);
...
...
src/app/shared/services/http-request.interceptor.ts
View file @
b75eec55
...
...
@@ -9,91 +9,80 @@ import {
import
{
BehaviorSubject
,
Observable
,
of
,
throwError
}
from
'rxjs'
;
import
{
catchError
,
filter
,
switchMap
,
take
,
tap
}
from
'rxjs/operators'
;
import
{
AuthService
}
from
'./auth.service'
;
import
{
environment
}
from
'src/environments/environment'
;
import
{
TokenService
}
from
'./token.service'
;
const
TOKEN_HEADER_KEY
=
'Authorization'
;
@
Injectable
()
export
class
HttpRequestInterceptor
{
private
isRefreshing
=
false
;
private
refreshTokenSubject
:
BehaviorSubject
<
string
|
null
>
=
new
BehaviorSubject
<
string
|
null
>
(
null
);
private
responseCache
=
new
Map
<
string
,
any
>
();
// ใช้เก็บ cache ของ response
constructor
(
private
authService
:
AuthService
)
{
}
// intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// if (req.url.startsWith("./") || !sessionStorage.getItem("accessToken")) {
// return next.handle(req);
// } else {
// const authHeader = 'Bearer ' + sessionStorage.getItem("accessToken")
// const overideReq = {
// headers: req.headers.set('Authorization', authHeader),
// url: req.url,
// };
// const authReq = req.clone(overideReq);
// return next.handle(authReq).pipe(tap(response => {
// this.responseCache.set(req.urlWithParams, response)
// }));
// }
// }
private
refreshTokenSubject
:
BehaviorSubject
<
any
>
=
new
BehaviorSubject
<
any
>
(
null
);
constructor
(
private
tokenService
:
TokenService
,
private
authService
:
AuthService
)
{
}
intercept
(
req
:
HttpRequest
<
any
>
,
next
:
HttpHandler
):
Observable
<
HttpEvent
<
any
>>
{
if
(
req
.
url
.
includes
(
'/api/auth/refresh-token'
)
||
req
.
url
.
startsWith
(
'./'
)
||
!
sessionStorage
.
getItem
(
'accessToken'
))
{
if
(
req
.
url
.
startsWith
(
"./"
))
{
return
next
.
handle
(
req
);
}
else
{
let
authReq
=
req
;
const
fullUrl
=
req
.
url
.
startsWith
(
"http"
)
?
req
.
url
:
environment
.
baseUrl
+
req
.
url
;
const
token
=
this
.
tokenService
.
getToken
()
if
(
token
!=
null
&&
!
req
.
url
.
includes
(
"/refresh-token"
))
{
authReq
=
this
.
addTokenHeader
(
req
,
token
,
fullUrl
);
}
else
{
const
overideReq
=
{
url
:
fullUrl
,
};
authReq
=
req
.
clone
(
overideReq
);
}
const
authHeader
=
'Bearer '
+
sessionStorage
.
getItem
(
'accessToken'
);
const
clonedReq
=
req
.
clone
({
headers
:
req
.
headers
.
set
(
'Authorization'
,
authHeader
)
});
return
next
.
handle
(
clonedReq
).
pipe
(
tap
(
response
=>
{
this
.
responseCache
.
set
(
req
.
urlWithParams
,
response
);
// เก็บ response cache
}),
catchError
((
error
:
HttpErrorResponse
)
=>
{
if
(
error
.
status
===
401
)
{
return
this
.
handle401Error
(
req
,
next
);
return
next
.
handle
(
authReq
).
pipe
(
catchError
(
error
=>
{
if
(
error
instanceof
HttpErrorResponse
&&
error
.
status
===
403
&&
!
fullUrl
.
includes
(
"login"
))
{
return
this
.
handle403Error
(
authReq
,
next
,
fullUrl
);
}
return
throwError
(()
=>
error
);
})
);
return
throwError
(
error
);
}));
}
private
handle401Error
(
req
:
HttpRequest
<
any
>
,
next
:
HttpHandler
):
Observable
<
HttpEvent
<
any
>>
{
if
(
this
.
isRefreshing
)
{
return
this
.
refreshTokenSubject
.
pipe
(
filter
(
token
=>
token
!==
null
),
take
(
1
),
switchMap
(
token
=>
{
const
clonedReq
=
req
.
clone
({
headers
:
req
.
headers
.
set
(
'Authorization'
,
`Bearer
${
token
}
`
)
});
return
next
.
handle
(
clonedReq
);
})
);
}
else
{
}
private
handle403Error
(
request
:
HttpRequest
<
any
>
,
next
:
HttpHandler
,
fullUrl
:
string
)
{
if
(
!
this
.
isRefreshing
)
{
this
.
isRefreshing
=
true
;
this
.
refreshTokenSubject
.
next
(
null
);
return
this
.
authService
.
refreshToken
().
pipe
(
switchMap
(
newTokens
=>
{
const
token
=
this
.
tokenService
.
getRefreshToken
();
if
(
token
)
return
this
.
authService
.
refreshToken
(
token
.
replace
(
"Bearer "
,
""
)).
pipe
(
switchMap
((
token
:
any
)
=>
{
this
.
isRefreshing
=
false
;
this
.
refreshTokenSubject
.
next
(
newTokens
.
accessToken
);
this
.
tokenService
.
saveToken
(
token
.
accessToken
);
this
.
tokenService
.
saveRefreshToken
(
token
.
refreshToken
);
this
.
refreshTokenSubject
.
next
(
token
.
accessToken
);
const
clonedReq
=
req
.
clone
({
headers
:
req
.
headers
.
set
(
'Authorization'
,
`Bearer
${
newTokens
.
accessToken
}
`
)
});
return
next
.
handle
(
clonedReq
);
return
next
.
handle
(
this
.
addTokenHeader
(
request
,
token
.
accessToken
,
fullUrl
));
}),
catchError
(
err
=>
{
catchError
((
err
)
=>
{
this
.
isRefreshing
=
false
;
this
.
authService
.
logout
();
return
throwError
(()
=>
new
Error
(
'Session expired, please log in again'
));
this
.
tokenService
.
signOut
();
return
throwError
(
err
);
})
);
}
}
}
return
this
.
refreshTokenSubject
.
pipe
(
filter
(
token
=>
token
!==
null
),
take
(
1
),
switchMap
((
token
)
=>
next
.
handle
(
this
.
addTokenHeader
(
request
,
token
,
fullUrl
)))
);
}
private
addTokenHeader
(
request
:
HttpRequest
<
any
>
,
token
:
string
,
fullUrl
:
string
)
{
/* for Spring Boot back-end */
// return request.clone({ headers: request.headers.set(TOKEN_HEADER_KEY, 'Bearer ' + token) });
/* for Node.js Express back-end */
return
request
.
clone
({
headers
:
request
.
headers
.
set
(
TOKEN_HEADER_KEY
,
token
)
,
url
:
fullUrl
});
}
}
src/app/shared/services/token.service.ts
View file @
b75eec55
import
{
Injectable
}
from
'@angular/core'
;
import
{
EmployeeModel
,
MyEmployeeModel
}
from
'../model/employee.model'
;
import
{
Router
}
from
'@angular/router'
;
import
{
UserModel
}
from
'../model/user.model'
;
const
TOKEN_KEY
=
'auth-token'
;
const
REFRESHTOKEN_KEY
=
'auth-refreshtoken'
;
const
USER_KEY
=
'auth-user'
;
const
USER_DATA_KEY
=
'auth-user-data'
;
export
class
UserLoginModel
{
public
username
:
string
=
""
;
public
accessToken
:
string
=
""
;
public
refreshToken
:
string
=
""
;
}
const
TOKEN_KEY
=
'accessToken'
;
@
Injectable
({
providedIn
:
'root'
providedIn
:
"root"
,
})
export
class
TokenService
{
constructor
(
private
router
:
Router
)
{
}
constructor
()
{
signOut
():
void
{
window
.
localStorage
.
clear
();
localStorage
.
clear
();
this
.
router
.
navigate
([
"/auth/splash"
]);
}
public
saveToken
(
token
:
string
):
void
{
window
.
localStorage
.
removeItem
(
TOKEN_KEY
);
window
.
localStorage
.
setItem
(
TOKEN_KEY
,
token
);
const
user
=
this
.
getUser
();
if
(
user
.
accessToken
)
{
this
.
saveUser
({
...
user
,
accessToken
:
token
});
}
}
public
getUser
():
any
{
const
user
=
this
.
decodeJWT
(
window
.
sessionStorage
.
getItem
(
TOKEN_KEY
)
!
)
public
saveUser
(
user
:
any
):
void
{
window
.
localStorage
.
removeItem
(
USER_KEY
);
window
.
localStorage
.
setItem
(
USER_KEY
,
JSON
.
stringify
(
user
));
}
public
getUser
():
UserLoginModel
{
const
user
=
window
.
localStorage
.
getItem
(
USER_KEY
);
if
(
user
)
{
return
user
;
return
JSON
.
parse
(
user
);
}
return
new
UserLoginModel
();
}
return
;
public
getToken
():
string
|
null
{
return
window
.
localStorage
.
getItem
(
TOKEN_KEY
);
}
decodeJWT
(
token
:
string
)
{
let
base64Url
=
token
.
split
(
'.'
)[
1
];
// ดึงส่วนที่เป็น Payload
let
base64
=
base64Url
.
replace
(
'-'
,
'+'
).
replace
(
'_'
,
'/'
);
// แก้ไข base64 ให้ถูกต้อง
let
jsonPayload
=
decodeURIComponent
(
atob
(
base64
).
split
(
''
).
map
(
function
(
c
)
{
return
'%'
+
(
'00'
+
c
.
charCodeAt
(
0
).
toString
(
16
)).
slice
(
-
2
);
}).
join
(
''
));
return
JSON
.
parse
(
jsonPayload
);
public
saveRefreshToken
(
token
:
string
):
void
{
window
.
localStorage
.
removeItem
(
REFRESHTOKEN_KEY
);
window
.
localStorage
.
setItem
(
REFRESHTOKEN_KEY
,
token
);
}
public
getRefreshToken
():
string
|
null
{
return
window
.
localStorage
.
getItem
(
REFRESHTOKEN_KEY
);
}
public
saveUserData
(
user
:
string
):
void
{
window
.
localStorage
.
removeItem
(
USER_DATA_KEY
);
window
.
localStorage
.
setItem
(
USER_DATA_KEY
,
user
);
}
public
getUserData
():
EmployeeModel
{
// return window.localStorage.getItem(USER_DATA_KEY);
const
user
=
window
.
localStorage
.
getItem
(
USER_DATA_KEY
);
if
(
user
)
{
return
new
MyEmployeeModel
(
JSON
.
parse
(
user
));
}
return
new
MyEmployeeModel
();
}
}
src/environments/environment.ts
View file @
b75eec55
...
...
@@ -3,18 +3,7 @@
// The list of file replacements can be found in `angular.json`.
export
const
environment
=
{
production
:
false
,
firebase
:
{
apiKey
:
'********************************'
,
authDomain
:
'********************************'
,
projectId
:
'********************************'
,
storageBucket
:
'********************************'
,
messagingSenderId
:
'********************************'
,
appId
:
'********************************'
,
measurementId
:
'********************************'
,
},
// baseUrl: 'https://hrplus-std.myhr.co.th/plus',
// baseUrl: 'https://192.168.10.165/plus',
baseUrl
:
' https://myskill-x.myhr.co.th/api'
,
baseUrl
:
' https://myskill-x-uat.myhr.co.th/api'
,
};
/*
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment