Passport
로그인 성공하면 accessToken, refrechToken 전달
@Post('login')
async login(@Body() input: LoginUserDto, @Res() res: Response) {
const { email, password } = input;
const query = `SELECT * FROM user WHERE email = '${email}'`;
const user = await this.userRepository.query(query);
if (user.length === 0) {
throw new HttpException('이메일 또는 비밀번호가 일치하지 않습니다.', HttpStatus.BAD_REQUEST);
}
const validPassword = await bcrypt.compare(password, user[0].password);
if (!validPassword) {
throw new HttpException('이메일 또는 비밀번호가 일치하지 않습니다.', HttpStatus.BAD_REQUEST);
}
this.authService.setRefreshToken({ user: user[0], res });
const jwt = this.authService.getAccessToken({ user: user[0] });
return res.status(200).json({
status: 200,
message: '로그인이 완료되었습니다.',
result: {
email: user[0].email,
name: user[0].name,
age: user[0].age,
phone: user[0].phone,
jwt,
},
});
}
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
@Injectable()
export class AuthService {
constructor(private readonly jwtService: JwtService) {}
getAccessToken({ user }): string {
return this.jwtService.sign(
{
email: user.email,
},
{
secret: process.env.ACCESS_TOKEN_SECRET_KEY,
expiresIn: '5s',
},
);
}
setRefreshToken({ user, res }) {
const refreshToken = this.jwtService.sign(
{
email: user.email,
},
{
secret: process.env.ACCESS_TOKEN_SECRET_KEY,
expiresIn: '2w',
},
);
// res.setHeader('Set-Cookie', `refreshToken=${refreshToken}`);
res.cookie('refreshToken', refreshToken, {
httpOnly: true,
path: '/',
maxAge: 60 * 60 * 24 * 14 * 1000, // 2주
// secure: true, // HTTPS 사용 시 주석 해제
// domain: 'localhost:3000', // 필요한 경우 도메인 설정
// sameSite: 'None', // 다른 도메인 간 요청에 필요
});
}
}
export const loginJWT_api = async (data: FormInputs1) =>
await axios
.post("http://localhost:8080/auth/login", data, {
withCredentials: true,
})
.then(res => res.data);
const login = useMutation({
mutationKey: ["login"],
mutationFn: (data: FormInputs1) => loginJWT_api(data),
onSuccess: res => {
alert("로그인이 완료되었습니다.");
sessionStorage.setItem("accessToken", res.result.jwt);
navigate("/board");
reset1();
},
onError: (err: any) => {
alert(err.response.data.message);
},
});
테스트를 위해 accessToken 유효시간을 5초로 해보았다
@UseGuards(AuthGuard('access'))
@Get('/user')
find(@Req() request: Request): Promise<Board> {
return this.boardService.findOne(+request.query.idx);
}
테스트를 위해 게시판 상세정보를 불러오는 api에만 @UseGuards(AuthGuard('access')) 데코레이터 적용
5초전에는 게시판 상세정보 api가 성공으로 날라오다가 5초 뒤엔 401로 accessToken이 만료되어 401로 날라온다
accessToken이 만료되었으니 refrechToken을 사용하여 accessToken을 재발급을 받아야한다.
프론트엔드 axios 설정
import axios from "axios";
export const tokenAxios = axios.create();
tokenAxios.interceptors.request.use(
config => {
const token = sessionStorage.getItem("accessToken");
if (token) {
config.headers["Authorization"] = `Bearer ${token}`;
}
return config;
},
error => {
return Promise.reject(error);
}
);
tokenAxios.interceptors.response.use(
response => {
return response;
},
error => {
const originalRequest = error.config;
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
axios
.post("http://localhost:8080/auth/refresh", {}, { withCredentials: true })
.then(res => {
console.log("res111", res);
});
}
return Promise.reject(error);
}
);
내일