diff --git a/src/main/java/com/example/bigbrotherbe/domain/member/entity/CustomerDetails.java b/src/main/java/com/example/bigbrotherbe/domain/member/entity/CustomerDetails.java new file mode 100644 index 0000000..e378ea9 --- /dev/null +++ b/src/main/java/com/example/bigbrotherbe/domain/member/entity/CustomerDetails.java @@ -0,0 +1,53 @@ +package com.example.bigbrotherbe.domain.member.entity; + +import java.util.Collection; +import java.util.stream.Collectors; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +@RequiredArgsConstructor +@Getter +public class CustomerDetails implements UserDetails { + + private final Member member; + @Override + public Collection getAuthorities() { + return member.getAffiliations().stream() + .map(affiliationMember -> new SimpleGrantedAuthority(affiliationMember.getRole())) + .collect(Collectors.toList()); + } + + @Override + public String getPassword() { + return member.getPassword(); + } + + @Override + public String getUsername() { + return member.getEmail(); + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } +} diff --git a/src/main/java/com/example/bigbrotherbe/domain/member/entity/Member.java b/src/main/java/com/example/bigbrotherbe/domain/member/entity/Member.java index a114b31..b31bd8b 100644 --- a/src/main/java/com/example/bigbrotherbe/domain/member/entity/Member.java +++ b/src/main/java/com/example/bigbrotherbe/domain/member/entity/Member.java @@ -37,7 +37,7 @@ @NoArgsConstructor(access = AccessLevel.PUBLIC) @AllArgsConstructor @EqualsAndHashCode(of = "id") -public class Member implements UserDetails { +public class Member { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -68,27 +68,6 @@ public class Member implements UserDetails { // 정적 필드로 정의된 정규식 패턴 객체 private static final Pattern EMAIL_PATTERN = Pattern.compile("^[A-Za-z0-9+_.-]+@(.+)$"); - @Override - public Collection getAuthorities() { - return this.affiliations.stream() - .map(affiliationMember -> new SimpleGrantedAuthority(affiliationMember.getRole())) - .collect(Collectors.toList()); - } - - @Override - public boolean isAccountNonExpired() { - return true; - } - - @Override - public boolean isAccountNonLocked() { - return true; - } - - @Override - public boolean isCredentialsNonExpired() { - return true; - } @Builder public Member(String username, String password, String email, String is_active, LocalDateTime createAt, LocalDateTime updateAt) { @@ -104,11 +83,6 @@ public Member(String username, String password, String email, String is_active, } - @Override - public boolean isEnabled() { - return true; - } - public void changePassword(String memberPass) { this.password = memberPass; } diff --git a/src/main/java/com/example/bigbrotherbe/global/jwt/JwtAuthenticationFilter.java b/src/main/java/com/example/bigbrotherbe/global/jwt/JwtAuthenticationFilter.java index ca6d0ed..4e9ef8f 100644 --- a/src/main/java/com/example/bigbrotherbe/global/jwt/JwtAuthenticationFilter.java +++ b/src/main/java/com/example/bigbrotherbe/global/jwt/JwtAuthenticationFilter.java @@ -5,28 +5,29 @@ import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; -import jakarta.servlet.ServletRequest; -import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; +import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.util.StringUtils; -import org.springframework.web.filter.GenericFilterBean; +import org.springframework.web.filter.OncePerRequestFilter; @RequiredArgsConstructor @Slf4j -public class JwtAuthenticationFilter extends GenericFilterBean { +public class JwtAuthenticationFilter extends OncePerRequestFilter { + private final JwtTokenProvider jwtTokenProvider; @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { - HttpServletRequest request = (HttpServletRequest) servletRequest; + protected void doFilterInternal(@NonNull HttpServletRequest servletRequest, + @NonNull HttpServletResponse servletResponse, + FilterChain filterChain) throws ServletException, IOException { try { - String token = resolveToken(request); + String token = resolveToken(servletRequest); if (token != null && jwtTokenProvider.validateToken(token) && jwtTokenProvider.checkTokenType(token)) { // 유효한 엑세스 토큰이 있는 경우 diff --git a/src/main/java/com/example/bigbrotherbe/global/jwt/component/AuthUtil.java b/src/main/java/com/example/bigbrotherbe/global/jwt/component/AuthUtil.java index f361899..ce5bc13 100644 --- a/src/main/java/com/example/bigbrotherbe/global/jwt/component/AuthUtil.java +++ b/src/main/java/com/example/bigbrotherbe/global/jwt/component/AuthUtil.java @@ -89,13 +89,13 @@ public Long getAffiliationIdByMemberId(Long memberId, String affiliation) { public JwtToken createAuthenticationToken(String email, String password) { UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(email, password); - Authentication authentication; try { - authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); + Authentication authentication = authenticationManagerBuilder.getObject() + .authenticate(authenticationToken); + return jwtTokenProvider.generateToken(authentication); } catch (Exception e) { throw new BusinessException(MISMATCH_PASSWORD); } - return jwtTokenProvider.generateToken(authentication); } } diff --git a/src/main/java/com/example/bigbrotherbe/global/jwt/component/JwtTokenProvider.java b/src/main/java/com/example/bigbrotherbe/global/jwt/component/JwtTokenProvider.java index e5674bf..5a4ae03 100644 --- a/src/main/java/com/example/bigbrotherbe/global/jwt/component/JwtTokenProvider.java +++ b/src/main/java/com/example/bigbrotherbe/global/jwt/component/JwtTokenProvider.java @@ -9,6 +9,7 @@ import com.example.bigbrotherbe.global.exception.enums.ErrorCode; import com.example.bigbrotherbe.global.jwt.entity.JwtToken; import com.example.bigbrotherbe.global.jwt.entity.TokenDto; +import com.example.bigbrotherbe.global.security.CustomUserDetailsService; import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.Jwts; @@ -19,8 +20,6 @@ import io.jsonwebtoken.security.Keys; import java.security.Key; -import java.util.Arrays; -import java.util.Collection; import java.util.Date; import java.util.stream.Collectors; @@ -42,9 +41,12 @@ public class JwtTokenProvider { private static final long ACCESS_TIME = 10 * 60 * 1000L; // 10분 private static final long REFRESH_TIME = 30 * 60 * 1000L; //30분 - public JwtTokenProvider(@Value("${jwt.secret}") String secretKey) { + private final CustomUserDetailsService customerDetailsService; + + public JwtTokenProvider(@Value("${jwt.secret}") String secretKey,CustomUserDetailsService customerDetailsService) { byte[] keyBytes = Decoders.BASE64.decode(secretKey); this.key = Keys.hmacShaKeyFor(keyBytes); + this.customerDetailsService = customerDetailsService; } // Member 정보를 가지고 Access Token, RefreshToken을 생성하는 메서드 @@ -80,21 +82,15 @@ public Authentication getAuthentication(String token) { if (claims.get("auth") == null) { throw new RuntimeException("권한 정보가 없는 토큰입니다."); } - - Collection authorities = - Arrays.stream(claims.get("auth").toString().split(",")) - .map(SimpleGrantedAuthority::new) - .collect(Collectors.toList()); - - UserDetails principal = new org.springframework.security.core.userdetails.User(claims.getSubject(), "", authorities); - log.info("Authorities from token: {}", authorities); - return new UsernamePasswordAuthenticationToken(principal, "", authorities); + UserDetails principal = customerDetailsService.loadUserByUsername( + claims.getSubject()); + return new UsernamePasswordAuthenticationToken(principal, "", principal.getAuthorities()); } public boolean validateToken(String token) { try { - Claims claims = Jwts.parserBuilder() + Jwts.parserBuilder() .setSigningKey(key) .build() .parseClaimsJws(token) @@ -188,4 +184,5 @@ private String resolveToken(String token) { } throw new BusinessException(ErrorCode.ILLEGAL_HEADER_PATTERN); } + } diff --git a/src/main/java/com/example/bigbrotherbe/global/security/CustomUserDetailsService.java b/src/main/java/com/example/bigbrotherbe/global/security/CustomUserDetailsService.java index 8630c6f..37769c2 100644 --- a/src/main/java/com/example/bigbrotherbe/global/security/CustomUserDetailsService.java +++ b/src/main/java/com/example/bigbrotherbe/global/security/CustomUserDetailsService.java @@ -1,9 +1,11 @@ package com.example.bigbrotherbe.global.security; +import com.example.bigbrotherbe.domain.member.entity.CustomerDetails; import com.example.bigbrotherbe.domain.member.entity.Member; import com.example.bigbrotherbe.domain.member.repository.MemberRepository; +import com.example.bigbrotherbe.global.exception.BusinessException; +import com.example.bigbrotherbe.global.exception.enums.ErrorCode; import lombok.RequiredArgsConstructor; -import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; @@ -16,15 +18,9 @@ public class CustomUserDetailsService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String userEmail) throws UsernameNotFoundException { - return memberRepository.findByEmail(userEmail).map(this::createUserDetails).orElseThrow(()-> new UsernameNotFoundException("해당하는 멤버를 찾을 수 없습니다.")); + Member member = memberRepository.findByEmail(userEmail).orElseThrow(() -> new BusinessException( + ErrorCode.NO_EXIST_EMAIL)); + return new CustomerDetails(member); } - // 해당하는 User 의 데이터가 존재한다면 UserDetails 객체로 만들어서 return - private UserDetails createUserDetails(Member member) { - return User.builder() - .username(member.getEmail()) - .password(member.getPassword()) - .authorities(member.getAuthorities()) - .build(); - } }