오류 및 문제점
1. UserDetails.getUsername()
- 문제점: 로그인을 시도할 때 UserVO의 변수가 userId이다.
- 해결 방안: UserDetails를 구현한 클래스에서 getUsername 시 userId를 반환하도록 한다.
@Override
public String getUsername() {
return user.getUserId();
}
2. payload 디코딩 시 한글 깨짐
- 문제점: 정보를 얻기 위해 payload를 디코딩하면 한글이 깨진다.
- 해결 방안: 한글은 2Byte이기 때문에 byte로 변환 후 디코딩해야 한다.
decodeStr = new String(decoder.decode(jwtstring.replace('.', '@').split("@")[1]), "UTF-8").trim();
3. payload 객체로 전달
- 문제점: front에서 로그인 정보를 사용하기 위해 JSON 객체로 전달하고자 한다.
- 해결 방안: json simple 라이브러리를 이용해 디코딩한 문자열을 JSON 객체로 변환한다.
JSONParser parser = new JSONParser();
JSONObject jsonObj = (JSONObject) parser.parse(decodeStr);
HeaderInfo info = HeaderInfo.builder()
.userno(jsonObj.get("userno"))
.uesrid(jsonObj.get("userid"))
.usernick(jsonObj.get("usernick")).build();
return info;
public class HeaderInfo {
private Object userno;
private Object uesrid;
private Object usernick;
}
진행상황
1. JWT 로그인/회원가입 예제
- 참고 자료에 있는 인프런 강의를 따라했다. 역시 설명을 들으며 하는 것이 잘 이해된다.
- 처음에는 이해가 잘 되지 않아 username, password 변수로 로그인 정보를 담을 LoginRequestDto를 따로 만들었었다. 로그인 인증을 할 때도 쓰이고 토큰을 검증할 때도 쓰여서 해당 형태로 DTO가 존재해야 한다고 생각했는데 이름이 비슷하다 보니 헷갈렸던 것 같다.
- 회원 속성이 많기 때문에 이제는 로그인에 필요한 정보만 LoginRequestDto로 만들어 로그인 요청 시에만 사용했다.
public class LoginRequestDto {
private String userId;
private String userPw;
}
user.setUserPw(bCryptPasswordEncoder.encode(user.getUserPw()));
user.setUserRole(Role.ROLE_USER);
userRepository.save(user);
response.addHeader(JwtProperties.HEADER_STRING, JwtProperties.TOKEN_PREFIX + jwtToken);
http.antMatchers("/user/**")
.access("hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')")
.antMatchers("/admin/**")
.hasRole("ADMIN")
.anyRequest()
.permitAll();
2. payload 디코딩
String jwtstring = request.getHeader("Authorization");
Base64.Decoder decoder = Base64.getUrlDecoder();
String decodeStr = new String(decoder.decode(jwtstring.replace('.', '@').split("@")[1]), "UTF-8").trim();
3. 비밀번호 확인
String user1 = userRepository.findByUserId("user1").getUserPw();
String test = "1234";
return bCryptPasswordEncoder.matches(test, user1) ? "같아" : "달라";
4. 실제 프로젝트에 적용
@PostMapping("/join")
public String join(@RequestBody UserVO user) {
ProfileVO profile = ProfileVO.builder().build();
user.setProfile(profile);
user.setUserPw(bCryptPasswordEncoder.encode(user.getUserPw()));
user.setUserRole(Role.ROLE_USER);
profile.setUser(user);
urepo.save(user);
return "회원가입 성공";
}
- user
- profile
5. 각종 유틸 묶음
public static String encodingUserPw(String userPw) {
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
return bCryptPasswordEncoder.encode(userPw);
}
public static boolean verifyUserPw(String rawPw, String encodedPw) {
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
return bCryptPasswordEncoder.matches(rawPw, encodedPw);
}
public static String getDecodedStr(String str) {
Base64.Decoder decoder = Base64.getUrlDecoder();
String decodeStr = null;
try {
decodeStr = new String(decoder.decode(str), "UTF-8").trim();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return decodeStr;
}
public static JSONObject getJsonObj(String str) {
JSONParser parser = new JSONParser();
JSONObject jsonObj = null;
try {
jsonObj = (JSONObject) parser.parse(str);
} catch (ParseException e) {
e.printStackTrace();
}
return jsonObj;
}
user.setUserPw(EncodingUtil.encodingUserPw(user.getUserPw()));
JSONObject jsonObj = JsonUtil.getJsonObj(decodeStr);
6. 회원가입 시 아아디 중복 체크
@PostMapping(value = "/join/useridCheck")
public boolean postUseridCheck(@RequestBody UserVO user) {
UserVO findUser = urepo.findByUserId(user.getUserId());
return findUser != null;
}
참고 자료