@angular-flow/oauth2
v0.9.6
Published
OAuth2 flow for Angular π±
Downloads
10
Maintainers
Readme
Angular OAuth2 Flow π«§
OAuth2 κΈ°λ°μ μΈμ¦μ λμμ£Όλ λΌμ΄λΈλ¬λ¦¬
- λ°λͺ¨ μ¬μ΄νΈ μμ κΈ°λ₯μ μ΄ν΄λ³Ό μ μμ΅λλ€.
μΈμ¦ νλ¦
μ€μ
λ¨Όμ @angular-flow/oauth2
λ₯Ό μ€μΉν©λλ€.
npm i @angular-flow/oauth2
app.config.ts
μ μλ μ½λλ₯Ό μΆκ°ν©λλ€.
// app.config.ts
...
export const appConfig: ApplicationConfig = {
providers: [
...
// oauth2 곡κΈμ μΆκ°
provideOAuth2({
refreshBehavior: RefreshTokensUsecase // RefreshBehaviorλ₯Ό ꡬννλ ν΄λμ€ λ±λ‘
// tokenStorage: <TokenStorage μΈν°νμ΄μ€λ₯Ό ꡬννλ ν΄λμ€> (μ ν)
// νμ΄λΈλ¦¬λμΉμ±μμλ μ 곡λλ `CapacitorStorage`λ‘ λ±λ‘ν΄μ£Όμλ©΄ λ©λλ€.
}),
provideHttpClient(
withInterceptors([
// oauth2 μΈν°μ
ν° μΆκ°
oauth2FlowInterceptor
])
),
]
};
λλ httpClient
λ₯Ό ν¬ν¨νλ νλ‘λ°μ΄λλ₯Ό λ±λ‘ν μ μμ΅λλ€.
export const appConfig: ApplicationConfig = {
providers: [
...
provideOAuth2WithHttpClient({
refreshBehavior: RefreshTokensUsecase, // νμλ±λ‘
interceptors: authMockInterceptors, // μ νμ¬ν
}),
],
};
OAuth2 νλ‘λ°μ΄λλ₯Ό λ±λ‘νκΈ° μν΄μ refreshBehavior
λ±λ‘μ νμμ
λλ€.
RefreshBehavior
μΈν°νμ΄μ€λ₯Ό ꡬννλ ν΄λμ€λ₯Ό μμ±νκ³ refresh
λ©μλμ λ°ννμ
μ λ§μ‘±νλλ‘ μ½λλ₯Ό μμ±ν΄μΌν©λλ€.
- refresh λ©μλλ OAuth2 λ΄λΆ μμ€ν μμ νΈμΆ λ©λλ€. μ΄ λ μΈμκ°μΌλ‘ νμ¬ μμ μ refreshTokenμ λκΈ°κΈ° λλ¬Έμ ν΄λΉ κ°μ νμ©νμ¬ μμ²μ λ³΄λΌ μ μμ΅λλ€.
@Injectable()
export class RefreshTokensUsecase implements RefreshBehavior {
private readonly httpClient = inject(HttpClient);
// @angular-flow/oauth2 μμ μ€μ λ ν ν° μ€ν λ¦¬μ§ μ£Όμ
private readonly tokenStorage = inject(TOKEN_STORAGE);
refresh(refreshToken: string): Observable<TokenResource> {
// λ°±μλμ μ½μλ λ°©μμΌλ‘ http νΈμΆ
const header = new HttpHeaders()
.set("Authorization", `Bearer ${refreshToken}`);
return this.httpClient.post<TokenResource>(REFRESH_TOKEN_MOCK_URL, {},{
headers: header,
// β
contextμ skipOAuth2Flow 컨ν
μ€νΈλ₯Ό μ¬μ©ν΄μΌν©λλ€.
// oauth2Flow μΈν°μ
ν°λ₯Ό 무μνκ³ μ§ννλλ‘ μ€μ ν©λλ€.
context: skipOAuth2Flow,
}).pipe(
// μμ² μ€ν¨ μ νμ²λ¦¬
catchError((res: HttpErrorResponse) => {
window.alert(res.error.message);
return throwError(() => res);
})
);
}
}
ν ν° μ€ν 리μ§λ₯Ό ν΅ν΄ ν ν°μ μ‘°ννκ±°λ μ μ₯, μμ ν μ μμ΅λλ€.
μλ₯Ό λ€μ΄, λ‘κ·ΈμΈ κΈ°λ₯μ ν΅ν΄ ν ν° λ¦¬μμ€λ₯Ό μ±κ³΅μ μΌλ‘ μ λ¬ λ°μ κ²½μ° μ 곡λλ TOKEN_STORAGE
νλ‘λ°μ΄λλ₯Ό νμ©νμ¬ ν ν° λ¦¬μμ€λ₯Ό μ μ₯ν©λλ€.
- ν ν°μ€ν 리μ§λ νμ΄λΈλ¦¬λ μ±μμ μ£Όλ‘ μ¬μ©λλ μ μ₯μ λΌμ΄λΈλ¬λ¦¬μΈ
Capacitor Preference
κΉμ§ λμνκΈ° λλ¬Έμ μ 곡λλ λ©μλλ€μ λͺ¨λPromise
λ°ννμ μ κ°μ§λλ€.
@Injectable()
export class LoginUsecase {
private readonly httpClient = inject(HttpClient);
private readonly tokenStorage = inject(TOKEN_STORAGE);
async execute(dto: ReqLoginDTO) {
// http μμ²
const http$ = this.httpClient.post<TokenResource>(LOGIN_MOCK_URL, dto).pipe(
catchError((res: HttpErrorResponse) => {
window.alert(res.error.message);
return throwError(() => res);
})
);
const res = await lastValueFrom(http$);
// ν ν°μ€ν 리μ§μ μλ΅κ° λ°ν
await this.tokenStorage.set(res);
}
}
μ΄μ μ μμ λ±λ‘λ httpClient
λ₯Ό μ¬μ©νμ¬ api μμ²μ μ§νν κ²½μ° λ€μκ³Ό κ°μ μΌλ€μ΄ μΌμ΄λ©λλ€.
- (ν ν°μ¬λ°κΈμ μ μΈν) λͺ¨λ API μμ²μ accessToken μ 무μ λ°λΌ Authorization ν΄λμ Bearer ννλ‘ μμΈμ€ν ν°μ μ£Όμ ν©λλ€.
- oauth2 μΈν°μ
ν°λ₯Ό κ±°μΉλ μμ²λ€μ μ€ν¨ μλ΅(401 Unauthorization error) μ λ±λ‘λ ν ν°μ¬λ°κΈ μΈν°νμ΄μ€λ₯Ό ν΅ν΄ ν ν° μ¬λ°κΈ μμ²μ μ§νν©λλ€.
- μ€ν¨νλ μμ²λ€μ λκΈ°μ΄ νμ μ μ₯λ©λλ€.
- ν ν° μ¬λ°κΈ μμ²μ΄ μ€ν¨λ‘ λλ κ²½μ°, ν ν° μ¬λ°κΈ μΈν°νμ΄μ€λ₯Ό ꡬνν ν΄λμ€μμ νμ²λ¦¬λ₯Ό ν μ μμ΅λλ€.
- μ€ν¨ μ oauth2 μλΉμ€μμ ν ν°μ€ν 리μ§λ₯Ό μλμΌλ‘ λΉμλλ€.
- ν ν° μ¬λ°κΈ μμ²μ΄ μ±κ³΅μ μ΄λ©΄ ν ν° λ¦¬μμ€λ₯Ό μλμΌλ‘ ν ν° μ€ν 리μ§μ λ€μ μ μ₯νκ² λ©λλ€.
- λκΈ°μ΄ νμ μ μ₯λ μμ²λ€λ μΌκ΄μ μΌλ‘ λ€μ μμ²νκ² λ©λλ€.