Java

[Spring Boot] Security @AuthenticationPricipal 객체로 로그인 정보 받는 방법

cob 2023. 3. 21. 17:56

 

@AuthenticationPricipal를 사용해 로그인한 사용자 정보를 받아올 수 있다.
하지만, @AuthenticationPricipal 입은 UserDetails이기 때문에 커스텀을 해줘야 한다.

 

 

1. 기존 Security + JWT 설정 방법

2022.10.25 - [Java] - [Spring Boot] Spring Security JWT를 사용한 토큰 인증 구현

 

 

 

 


2.  UserDetails을  커스텀한 클래스를 작성한다.

@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CustomUserDetails implements UserDetails {

    private String username; 
    private String password;
    private String authority;
    private boolean enabled;
    private Collection<? extends GrantedAuthority> authorities;
    private boolean isEnabled;
    private boolean isAccountNonExpired;
    private boolean isAccountNonLocked;
    private boolean isCredentialsNonExpired;
    
    /* 추가 */
    private String user_name;
    private String nickname;
    private int phone;
}
  • UserDetails 인터페이스를 상속받고, 추가하고 싶은 변수들을 작성한다.

 

 

 


2. TokenProvider.java (JWT 토큰 발행) 

매번 DB접속을 하지 않기 위해 토큰에 기본 정보를 담았다.
@Slf4j
@Service
public class TokenProvider {

    // 설정한 토큰 값
    @Value("${SECRET_KEY}")
    private String SECRET_KEY;

    public String create(UserEntity userEntity) {
        // 기한은 지금부터 1일로 설정
        Date expiryDate = Date.from(
                Instant.now()
                        .plus(1, ChronoUnit.DAYS));


            // JWT Token 생성
            return Jwts.builder()
                .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
                .claim("id", userEntity.getId())
                .claim("user_name", userEntity.getUser_name())
                .claim("nickname", userEntity.getNickname())
                .claim("phone", userEntity.getPhone())
                .claim("role", userEntity.getRole())
                .setSubject(userEntity.getId()) 
                .setIssuedAt(new Date())		
                .setExpiration(expiryDate)		
                .compact();
    }
    /**
     * 토큰의 Claim 디코딩
     */
    public Claims getAllClaims(String token) {
        return Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody();
    }
}

 

 

 

 


3. JwtAuthenticationFilter.java (JWT 인증 필터) 

토큰이 가지고 있는 정보를 가지고 커스텀했던 UserDetail 객체를 만든다.

@Slf4j
@Component
public class JwtAuthenticationFilter  extends OncePerRequestFilter {

    @Autowired
    private TokenProvider tokenProvider;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            // 요청에서 토큰 가져오기
            String token = parseBearerToken(request);

            // 토큰 검사하기. JWT이므로 인가 서버에 요청하지 않고도 검증 가능
            if(token != null && !token.equalsIgnoreCase(null)) {
                
                // 토큰 정보를 가져온다.
                Claims claims = tokenProvider.getAllClaims(token);
         
                // 커스텀한 UserDetail 객체를 생성한다 
                CustomUserDetails userDetails = CustomUserDetails.builder()
                        .username((String) claims.get("id"))
                        .nickname((String) claims.get("nickname"))
                        .user_name((String) claims.get("user_name"))
                        .password((String) claims.get("password"))
                        .phone((int) claims.get("phone"))
                        .authorities(Arrays.asList(new SimpleGrantedAuthority((String) claims.get("role"))))
                        .isAccountNonExpired(true)
                        .isAccountNonLocked(true)
                        .isCredentialsNonExpired(true)
                        .build();

                //인증 완료. SecurityContextHolder에 등록해야 인증된 사용자라고 생가한다.
                AbstractAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                        userDetails, 
                        null,
                        AuthorityUtils.NO_AUTHORITIES
                );
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
                securityContext.setAuthentication(authentication); 	// 인증 정보 넣기
                SecurityContextHolder.setContext(securityContext);	// 다시 등록
            }
        } catch (Exception ex) {
            logger.error("시큐리티 필터 오류", ex);
        }

        filterChain.doFilter(request, response);
    }

    private String parseBearerToken(HttpServletRequest request) {
        // Http 요청의 헤더를 파싱해 Bearer 토큰을 리턴한다.
        String bearerToken = request.getHeader("Authorization");

        if(StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }
}

 

 

 

 


4. Controller에 로그인 정보 가져오기

@AuthenticationPricipal을 활용하여 CustomUserDetails를 가져온다.
@Slf4j
@RestController
@RequestMapping("comment")
public class CommentsController {
 ...
 
   @PostMapping("/new")
    public ResponseEntity<?> commentsInsert(@AuthenticationPrincipal CustomUserDetails user, @RequestBody CommentDTO dto){
        try {
            dto.setUser_id(user.getNickname());
            List<Map> comments = service.commentCreate(dto);
            return ResponseEntity.ok().body(comments);
        } catch (HttpClientErrorException e) {
            String error = e.getMessage();
            ResponseDTO<CommentDTO> response = ResponseDTO.<CommentDTO>builder().error(error).build();
            return ResponseEntity.badRequest().body(response);
        }
    }
 }

 

 

 

반응형