๋ก๊ทธ์ธ
JWT ๊ธฐ๋ฐ์ ๋ก๊ทธ์ธ ๊ธฐ๋ฅ์ ๊ตฌํํ๋ค. ์ ์ฒด์ ์ธ ๋ก์ง์ ๋ค์๊ณผ ๊ฐ๋ค.
1. ์ฌ์ฉ์ ๋ก๊ทธ์ธ ์์ฒญ
2. ์ฌ์ฉ์ ํ์ธ ํ, access token๊ณผ refresh token ๋ฐ๊ธ
3. refresh token์ Redis์ ์ ์ฅ
4. ํ ํฐ ์ฌ๋ฐ๊ธ ์์ฒญ ์, Redis์ refresh token ์ ๋ณด๊ฐ ์กด์ฌํ๋์ง ํ์ธ ํ ๋ฐ๊ธ
5. ๋ก๊ทธ์์ ์, Redis์ refresh token ์ ๋ณด ์ญ์
access token์ 30๋ถ, refresh token์ 2์ฃผ์ ์ ํจ๊ธฐ๊ฐ์ ๋์๋ค. refresh token์ ๊ฒฝ์ฐ ์ ํจ๊ธฐ๊ฐ์ด ๊ธธ๊ธฐ ๋๋ฌธ์, ์๋ฒ์ฌ์ด๋์์ ๊ด๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋๋ก Redis์ ์ ์ฅํ๋ค. refresh token์ ํตํด ํ ํฐ ์ฌ๋ฐ๊ธ ์์ฒญ ์, refresh token์ ์ ํจ์ฑ ์ฌ๋ถ ๋ฟ๋ง์๋๋ผ Redis์ refresh token ์ ๋ณด๊ฐ ์กด์ฌํ๋์ง ํ์ธ ํ ํ ํฐ์ ์ฌ๋ฐ๊ธํ๋ค. ๋ก๊ทธ์์ ์์ Redis์ ํด๋น ์ฌ์ฉ์์ refresh token์ ์ญ์ ํ๊ธฐ ๋๋ฌธ์, ๋ก๊ทธ์์ ์ํ์์ ํ ํฐ์ ์ฌ๋ฐ๊ธ ํ ์ ์๋ ๊ตฌ์กฐ์ด๋ค.
UserService.java
@RequiredArgsConstructor
@Service
public class UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final JwtUtil jwtUtil;
private final MailUtil mailUtil;
private final RedisUtil redisUtil;
public TokenResponseDto signin(SigninRequestDto signinRequestDto) {
String email = signinRequestDto.getEmail();
String password = signinRequestDto.getPassword();
User user = userRepository.findByEmail(email);
if(user==null) throw new EmailNotExistException(email);
userRepository.updateAccessedAt(user.getId(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
if(!passwordEncoder.matches(password, user.getPasswd())) throw new PasswordWrongException();
String accessToken = jwtUtil.createToken(user.getId(), user.getEmail(), user.getNickname(), user.getRole(), "ACCESS_TOKEN", 30);
String refreshToken = jwtUtil.createToken(user.getId(), user.getEmail(), user.getNickname(), user.getRole(), "REFRESH_TOKEN", 60*24*14);
redisUtil.set(refreshToken, user.getRole(), 60*24*14);
return TokenResponseDto.builder()
.id(user.getId())
.email(email)
.nickname(user.getNickname())
.role(user.getRole())
.accessToken(accessToken)
.refreshToken(refreshToken)
.build();
}
public void signout(String refreshToken) {
if(!redisUtil.delete(refreshToken)) throw new SignoutException();
}
public TokenResponseDto refreshToken(String refreshToken) throws ExpiredJwtException {
// ๋ก๊ทธ์์ ์ํ์์ refresh ์์ฒญ
if(!redisUtil.hasKey(refreshToken)) throw new UnauthorizedException();
Claims claims = jwtUtil.getClaims(refreshToken);
int userId = (int) claims.get("userId");
String email = claims.getSubject();
String nickname = (String) claims.get("nickname");
int role = (int) claims.get("role");
String accessToken = jwtUtil.createToken(userId, email, nickname, role, "ACCESS_TOKEN", 30);
return TokenResponseDto.builder()
.id(userId)
.email(email)
.nickname(nickname)
.role(role)
.accessToken(accessToken)
.refreshToken(refreshToken)
.build();
}
}
ํ ํฐ ๊ฒ์ฌ ๋ฐ ์ฌ์ฉ
์ธ์ฆ์๋ฒ์์ ๋ฐ๊ธ ๋ฐ์ ํ ํฐ์ ๋ค๋ฅธ ์๋น์ค ์๋ฒ์์ ์ฌ์ฉ์ ์ธ์ฆ ๋ฐ ์ ๋ณด ์ ๊ณตํ๋๋ฐ ์ฌ์ฉ๋๋ค. ๋๋ ํ์ฌ ๊ฐ๋ฐ ์ค์ธ ์๊ธฐ์๊ฐ์ ์๋ฒ์์, ์ธํฐ์ ํฐ๋ฅผ ํตํด ํ ํฐ์ ์ ํจ์ฑ์ ๊ฒ์ฌํ๊ณ , ๊ฐ๊ฐ์ ์์ฒญ์ ๋ง๊ฒ ์๋น์ค ๋จ์์ ํ ํฐ์ ๋ด๊ธด ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ํตํด, ์์ฒญํ ๋ฆฌ์์ค(์๊ธฐ์๊ฐ์ ๋ฑ)์ ์ ๊ทผ ๊ฐ๋ฅํ์ง ์ฌ๋ถ ๋ฑ์ ํ๋จํ๋ค.
ํ์ฌ ๊ฐ๋ฐ ์ค์ธ ์๋น์ค์์๋ ๊ฐ๊ฐ์ ์๋น์ค ์๋ฒ๊ฐ ํ ํฐ์ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ๊ฐ์ ์ํํ์ง๋ง, API Gateway๋ฅผ ๊ฐ๋ฐํ๊ฒ ๋๋ฉด ํด๋น ๋ก์ง์ ํ๋ฒ์ ์ฒ๋ฆฌํ ์ ์์๋ฏ ํ๋ค.
JwtCheckInterceptor.java
@Component
public class JwtCheckInterceptor implements HandlerInterceptor {
@Autowired
private JwtUtil jwtUtil;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = jwtUtil.getToken(request);
if(token.equals("Bearer")) throw new TokenNotExistException();
if(!(jwtUtil.isValidToken(token) && jwtUtil.isAccessToken(token))) {
throw new InvalidTokenException();
}
return true;
}
}
WebMvcConfig.java
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private JwtCheckInterceptor jwtCheckInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtCheckInterceptor).addPathPatterns("/**");
}
}
ResumeService.java
@RequiredArgsConstructor
@Service
public class ResumeService {
private final ResumeRepository resumeRepository;
private final JwtUtil jwtUtil;
public ResumeDetailResponseDto getResume(String token, int resumeId) {
if(!checkAuth(token, resumeId)) return null;
Resume resume = resumeRepository.findResumeById(resumeId);
List<Answer> answers = resumeRepository.findAnswersByResumeId(resumeId);
return ResumeDetailResponseDto.builder()
.resume(resume)
.answers(answers)
.build();
}
private boolean checkAuth(String token, int resumeId) {
Resume resume = resumeRepository.findResumeById(resumeId);
if(resume == null) throw new ResumeNotExistException(resumeId);
int userId = getUserId(token);
if(userId != resume.getUserId()) throw new UnauthorizedException();
return true;
}
private int getUserId(String token) {
Claims claims = jwtUtil.getClaims(token.substring("Bearer ".length()));
return (int) claims.get("userId");
}
}
'์ค๋ง์ผ๊ฒ์ดํธ ์๋ฒ๊ฐ๋ฐ์บ ํ 4๊ธฐ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[์๋ฒ๊ฐ๋ฐ์บ ํ] ์ธ์ฆ ์๋ฒ - ๋ก๊ทธ์ธ ์ฑ๋ฅ ํ ์คํธ : nGrinder (0) | 2020.02.15 |
---|---|
[์๋ฒ๊ฐ๋ฐ์บ ํ] ์ธ์ฆ ์๋ฒ - AWS EC2 & RDS ๊ตฌ์ถ ๋ฐ ๋ฐฐํฌ (0) | 2020.02.10 |
[์๋ฒ๊ฐ๋ฐ์บ ํ] ์ธ์ฆ ์๋ฒ - ์ด๋ฉ์ผ ์ธ์ฆ ํ์๊ฐ์ (0) | 2020.02.08 |
[์๋ฒ๊ฐ๋ฐ์บ ํ] ์ธ์ฆ ์๋ฒ - Spring Security + JWT (0) | 2020.02.02 |
๐ ์๋ฒ๊ฐ๋ฐ์บ ํ 4๊ธฐ (0) | 2020.01.12 |