BE전문가 프로젝트
4-1 Authentication(인증) - UserDetails, UserDetailsService 및 JwtService 생성 본문
SpringBoot Security
4-1 Authentication(인증) - UserDetails, UserDetailsService 및 JwtService 생성
원호보고서 2023. 7. 9. 20:210. 프로젝트 소개(Spring Security) 및 Security에 대하여
1. User Entity 생성(Spring Security)
2. User 회원가입 (Spring Secureity)
3.Jwt의 사용 이유 (Spring Security)
4. Authorization(인증)
- 4-0 Authorization(인증) - 프로세스 설명
- 4-1 Authentication(인증) - UserDetails, UserDetailsService 및 JwtService 생성
- 4-2 Authentication(인증) - UsernamePasswordAuthenticationfilter 생성
- 4-3 Authentication(인증) - CorsFilter(선택사항)
- 4-4 Authentication(인증) - SecurityConfig
5. Authorization(인가)
- 5-1 Authorization(인가) - Jwt 인가 관련 에러 처리
- 5-2 Authorization(인가) - Jwt 인가 서비스 로직 추가
- 5-3 Authorization(인가) - AuthorizationFilter 생성
- 5-4 Authorization(인가) - SecurityConfig에 인가 관련 method 추가
6. OAuth
LoginDto 생성
public class LoginDto {
@Getter
public static class LoginRequestDto {
private String email;
private String password;
}
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class LoginResponseDto {
private long userId;
private String email;
private String password;
private String nickName;
private String profileUrl;
private String refreshToken;
private String userRole;
private SocialType socialType;
public List<String> getRoleList(){
if(this.userRole.length() > 0){
return Arrays.asList(this.userRole.split(","));
}
return new ArrayList<>();
}
}
login에서 사용할 Dto를 만들어 준다.
public List<String> getRoleList(){
if(this.userRole.length() > 0){
return Arrays.asList(this.userRole.split(","));
}
return new ArrayList<>();
}
- UserDetail에서 권한을 가져올 때 Return 타입이 Collection이기 때문에 만들어준 함수
PrincipalDetails생성
/**
* @package com.example.spring_security.config.security.auth
* @class PrincipalDetails
* @brief 권합 삽입
* @details 사용자에 해당하는 권한을 넣어준다
* 시큐리티가 가지고 있는 시큐리티_session에 들어갈 수 있는 Object는 정해져 있음(Object == Authentication객체)
* @author 최원호
* @date 2023.05.02
* version 1.0
*/
public class PrincipalDetails implements UserDetails {
private LoginResponseDto loginResponseDto;
public PrincipalDetails(LoginResponseDto loginResponseDto) {
this.loginResponseDto = loginResponseDto;
}
/**
* @details 사용자 정보에 권한을 삽입한다.
* @return 권한
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new ArrayList<>();
loginResponseDto.getRoleList().forEach(r -> {
authorities.add(()->{ return r;});
});
return authorities;
}
/**
* @brief 패스워드 호출.
* @return 패스워드
*/
@Override
public String getPassword() {
return loginResponseDto.getPassword();
}
/**
* @brief 유저네임 호출.
* @return 이메일
*/
@Override
public String getUsername() {
return loginResponseDto.getEmail();
}
/**
* @brief 계정의 만료 여부 리턴
* @return true
*/
@Override
public boolean isAccountNonExpired() {
return true;
}
/**
* @brief 계정의 잠금 여부 리턴
* @return true
*/
@Override
public boolean isAccountNonLocked() {
return true;
}
/**
* @brief 비밀번호 만료 여부 리턴
* @return true
*/
@Override
public boolean isCredentialsNonExpired() {
return true;
}
/**
* @brief 계정의 활성화 여부 리턴
* @return true
*/
@Override
public boolean isEnabled() {
return true;
}
}
UserDetails
- Spring Security에서 사용자의 정보를 담는 인터페이스
PrincipalDetailsService생성
/**
* @package com.example.spring_security.config.security.auth
* @class PrincipalDetailsService
* @brief 사용자의 정보를 가져오기 위한 비즈니스 로직
* @author 최원호
* @date 2023.06.22
* version 1.0
*/
@Slf4j
@Service
public class PrincipalDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userRepository.findByEmail(email).orElseThrow();
LoginResponseDto loginResponseDto = LoginResponseDto.builder()
.userId(user.getUserId())
.email(user.getEmail())
.password(user.getPassword())
.nickName(user.getNickname())
.profileUrl(user.getProfileUrl())
.refreshToken(user.getRefreshToken())
.userRole(user.getUserRole())
.build();
return new PrincipalDetails(loginResponseDto);
}
}
UserDetailsService
- Spring Security에서 유저의 정보를 가져오는 인터페이스
JwtService생성
package com.example.spring_security.config.security.jwt.Service;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.example.spring_security.config.security.jwt.JwtProperties;
import com.example.spring_security.config.security.jwt.dto.LoginDto.LoginResponseDto;
import com.example.spring_security.user.domain.User;
import com.example.spring_security.user.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.minidev.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
/**
* @package com.example.spring_security.config.security.jwt.Service
* @class JwtServiceImpl
* @brief jwt 비즈니스로직 구현 클래스
* @author 최원호
* @date 2023.06.22
* version 1.0
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class JwtServiceImpl implements JwtService {
@Value("${jwt.secret}")
private String SECRET_KEY;
private final UserRepository userRepository;
/**
* @brief 토큰 생성
* @param email
* @return accessToken
*/
@Override
public String createAccessToken(String email) {
return JWT.create()
.withSubject(JwtProperties.ACCESS_TOKEN)
.withClaim(JwtProperties.EMAIL, email)
.withExpiresAt(new Date(System.currentTimeMillis()+JwtProperties.EXPIRATION_TIME))
.sign(Algorithm.HMAC512(SECRET_KEY));
}
/**
* @brief refresh 토큰 생성
* @return refreshToken
*/
@Override
public String createRefreshToken() {
return JWT.create()
.withSubject(JwtProperties.REFRESH_TOKEN)
.withExpiresAt(new Date(System.currentTimeMillis()+JwtProperties.EXPIRATION_TIME))
.sign(Algorithm.HMAC512(SECRET_KEY));
}
/**
* @brief email을 통한 유저 entity 조회
* @param email
* @return LoginResponseDto
*/
@Override
public LoginResponseDto retrieveByEmail(String email) {
User user = userRepository.findByEmail(email).orElseThrow();
return LoginResponseDto.builder().userId(user.getUserId())
.email(user.getEmail())
.password(user.getPassword())
.nickName(user.getNickname())
.profileUrl(user.getProfileUrl())
.refreshToken(user.getRefreshToken())
.userRole(user.getUserRole())
.socialType(user.getSocialType())
.build();
}
/**
* @brief refreshToken 수정
* @param userId
* @param refreshToken
*/
@Override
@Transactional
public void setRefreshToken(long userId, String refreshToken) {
userRepository.findById(userId).orElseThrow().updateRefreshToken(refreshToken);
}
/**
* @brief accessToken Header에 설정
* @param response
* @param accessToken
*/
@Override
public void setAccessTokenToHeader(HttpServletResponse response, String accessToken) {
response.setHeader(JwtProperties.ACCESS_TOKEN_HEADER,JwtProperties.TOKEN_PREFIX + accessToken);
}
/**
* @brief refreshToken Header에 설정
* @param response
* @param refreshToken
*/
@Override
public void setRefreshTokenToHeader(HttpServletResponse response, String refreshToken) {
response.setHeader(JwtProperties.REFRESH_TOKEN_HEADER, JwtProperties.TOKEN_PREFIX + refreshToken);
}
/**
* @brief 결과 메시지 구현
* @param result
* @param response
* @param message
*/
@Override
public void setResponseMessage(boolean result, HttpServletResponse response, String message) throws IOException {
JSONObject jObject = new JSONObject();
response.setContentType("application/json;charset=UTF-8");
if(result){
response.setStatus(HttpServletResponse.SC_OK);
jObject.put("success", true);
jObject.put("code", 200);
jObject.put("message", message);
} else {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
jObject.put("success", false);
jObject.put("code", 999);
jObject.put("message", message);
}
response.getWriter().print(jObject);
}
}
@Override
public String createAccessToken(String email) {
return JWT.create()
.withSubject(JwtProperties.ACCESS_TOKEN)
.withClaim(JwtProperties.EMAIL, email)
.withExpiresAt(new Date(System.currentTimeMillis()+JwtProperties.EXPIRATION_TIME))
.sign(Algorithm.HMAC512(SECRET_KEY));
}
- withSubject: 토큰의 이름
- withClaim: 토큰에 담고싶은 정보
- withExpiresAt: 토큰의 유효기간
- sign: 토큰의 암호화 알고리즘
'SpringBoot Security' 카테고리의 다른 글
4-3 Authentication(인증) - CorsFilter(선택사항) (0) | 2023.07.09 |
---|---|
4-2 Authentication(인증) - UsernamePasswordAuthenticationfilter 생성 (0) | 2023.07.09 |
4-0 Authorization(인증) - 프로세스 설명 (0) | 2023.07.08 |
3. Jwt의 사용 이유 (Spring Security) (0) | 2023.06.28 |
2. User 회원가입 (Spring Secureity) (0) | 2023.06.27 |
Comments