이번 시간은 front에서 jwt 토큰을 추가하여 사용자 조회를 하고, 권한 관리를 하는 기능을 구현 해 봅니다.
백엔드(slider-api)
토큰 Validation
권한 관리를 위해 JWT Token validation을 추가 합니다.
이것은 사용자가 header에 token을 보냈을때 사용자 정보를 조회하는 기능입니다.
/src/auth/security/passport.jwt.strategy.ts
async validate(payload: Payload, done: VerifiedCallback): Promise<any> {
const user = await this.authService.tokenValidateUser(payload);
if(!user) {
return done(new UnauthorizedException({message: 'user does not exist'}), false);
}
return done(null, user);
}
authService에 tokenValidateUser를 추가합니다.
/src/auth/auth.service.ts
async tokenValidateUser(payload: Payload): Promise<User| undefined> {
const userFind = await this.userService.findByFields({
where: { id: payload.id }
});
this.flatAuthorities(userFind);
return userFind;
}
private flatAuthorities(user: any): User {
if (user && user.authorities) {
const authorities: string[] = [];
user.authorities.forEach(authority => authorities.push(authority.authorityName));
user.authorities = authorities;
for(const auth of authorities){
if(auth === RoleType.ADMIN){
user.isAdmin = true;
}
}
}
return user;
}
로그인한 사용자만 접근할 수 있도록 Auth Guard를 만듭니다.
/src/auth/security/auth.guard.ts
import { ExecutionContext, Injectable, UnauthorizedException } from "@nestjs/common";
import { AuthGuard as NestAuthGuard } from "@nestjs/passport";
import { Observable } from "rxjs";
@Injectable()
export class AuthGuard extends NestAuthGuard('jwt'){
canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
return super.canActivate(context)
}
handleRequest(err, user, info) {
if (err || !user) {
throw err || new UnauthorizedException();
}
return user;
}
}
권한별로 접근할 수 있도록 Role Guard를 만듭니다.
여기서는 일반 사용자와 관리자 권한을 체크하려고 합니다.
/src/auth/security/role.guard.ts
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { User } from '../../domain/user.entity';
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private readonly reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const roles = this.reflector.get<string[]>('roles', context.getHandler());
if (!roles) {
return true;
}
const request = context.switchToHttp().getRequest();
const user = request.user as User;
console.log(`auth include : ${user.authorities.some(role => roles.includes(role))}`)
return user && user.authorities && user.authorities.some(role => roles.includes(role));
}
}
AuthController에서 사용자 정보를 조회하는 API를 추가합니다.
이 api는 "/auth/user"를 통해 호출할 수 있으며,
@UseGuards(AuthGuard)를 사용하였으므로 로그인한 사용자만 사용이 가능합니다.
/src/auth/auth.controller.ts
// 사용자 정보 조회
@UseGuards(AuthGuard)
@Get('/user')
getUser(@Request() req): any {
console.log(req);
return req.user;
}
프론트엔드(slider-front)
사용자 정보 조회
이제 front에서 로그인 후 사용자 정보를 조회하는 로직을 추가합니다.
우선 store에 user와 isAdmin을 추가합니다.
/store/index.js
export const state = () => ({
accessToken: '',
user: '',
});
export const mutations = {
accessToken (state, data) {
state.accessToken = data;
},
user (state, data) {
state.user = data;
},
}
로그인 후 api를 호출해 사용자 정보를 조회하고 store에 저장합니다.
/pages/kakao-callback.vue
const response = await this.$axios.$post(
'/auth/login', body, {}
)
if(response){
const accessToken = response.accessToken;
console.log(accessToken);
// 토큰을 스토어에 저장하기
this.$store.commit('accessToken', accessToken);
const options = {
headers: {
Authorization: `Bearer ${accessToken}`
},
};
//토큰을 이용하여 사용자 정보 조회하기
const user = await this.$axios.get("/auth/user", options);
const loginUser = user.data;
console.log(loginUser);
this.$store.commit('user', loginUser);
}
return this.$router.push('/')
Navigation에서 관리자일 경우만 관리자 링크를 보여주도록 추가합니다.
/layouts/default.vue
<template>
<div>
<b-navbar toggleable="lg" type="dark" variant="info">
<b-navbar-brand href="#">Slider</b-navbar-brand>
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
<b-collapse id="nav-collapse" is-nav>
<b-navbar-nav class="ml-auto" v-if="!accessToken">
<b-nav-item href="/login" right>로그인</b-nav-item>
</b-navbar-nav>
<b-navbar-nav class="ml-auto" v-if="accessToken && accessToken!==''">
<b-nav-item @click="admin" right v-if="user.isAdmin">관리자</b-nav-item>
<b-nav-item @click="logout" right>로그아웃</b-nav-item>
</b-navbar-nav>
</b-collapse>
</b-navbar>
<nuxt/>
</div>
</template>
<script>
export default {
name: 'Layout',
data() {
return {
auth: false
}
},
mounted() {
this.$nuxt.$on('auth', auth=>{
this.auth = auth
console.log(auth)
})
},
methods: {
async logout() {
await this.$store.commit('accessToken', '');
await this.$router.push('/');
},
async admin() {
alert('관리자 메뉴!!!')
}
},
computed: {
accessToken() {
return this.$store.state.accessToken
},
user() {
return this.$store.state.user;
},
}
}
</script>
테스트
로그인 테스트를 하면 다음과 같은 결과를 확인할 수 있습니다.
MySQL의 user_authority 테이블에 관리자 권한을 추가합니다.
다시 로그인 테스트를 하면 관리자 메뉴가 추가된걸 보실 수 있습니다.
* 참고로 백엔드에서 admin 권한 체크를 하실때는 controller에 다음과 같이 데코레이터를 추가하시면 됩니다.
@UseGuards(AuthGuard,RolesGuard)
@Roles(RoleType.ADMIN)
'Nestjs 활용 동영상강좌' 카테고리의 다른 글
(풀스택) Node(Nest)와 Vue(Nuxt)로 사이트 만들기 - 11.이미지 조회 및 삭제 (0) | 2022.12.18 |
---|---|
(풀스택) Node(Nest)와 Vue(Nuxt)로 사이트 만들기 - 10.업로드 파일 DB 저장 (0) | 2022.12.11 |
(풀스택) Node(Nest)와 Vue(Nuxt)로 사이트 만들기 - 09.Front에서 S3에 파일 업로드하기 (0) | 2022.10.23 |
(풀스택) Node(Nest)와 Vue(Nuxt)로 사이트 만들기 - 08.AWS S3 설정 (0) | 2022.10.22 |
(풀스택) Node(Nest)와 Vue(Nuxt)로 사이트 만들기 - 06.Front 로그인 (with Jwt Token) (0) | 2022.10.03 |
(풀스택) Node(Nest)와 Vue(Nuxt)로 사이트 만들기 - 05.JWT인증 (0) | 2022.10.01 |
(풀스택) Node(Nest)와 Vue(Nuxt)로 사이트 만들기 - 04.카카오 로그인 (2) | 2022.09.24 |
(풀스택) Node(Nest)와 Vue(Nuxt)로 사이트 만들기 - 03.TypeORM 설정 (0) | 2022.09.13 |