Skip to content

Commit

Permalink
Merge pull request #92 from HongDam-org/feat/refactor-security-member
Browse files Browse the repository at this point in the history
[REFACTOR] 멤버 및 시큐리티 리팩토링
  • Loading branch information
ohksj77 authored Apr 1, 2024
2 parents 8fb851e + fa3b5e7 commit 600acd3
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {

private static final String[] AUTH_WHITELIST = {
"/auth/refresh",
"/auth/save",
"/auth/login",
"/member/duplicate/**",
"/location/**",
"/actuator/**"};
private final JwtFilter jwtFilter;
private final JwtAccessDeniedHandler jwtAccessDeniedHandler;
private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
Expand All @@ -30,14 +38,7 @@ public SecurityFilterChain configure(HttpSecurity http) throws Exception {
.formLogin(f -> f.disable())
.authorizeHttpRequests(
x ->
x.requestMatchers(
"/auth/refresh",
"/auth/save",
"/auth/login",
"/member/duplicate/**",
"/location/**",
"/actuator/**",
"/member/test/**")
x.requestMatchers(AUTH_WHITELIST)
.permitAll()
.anyRequest()
.authenticated())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.Optional;

@Component
@RequiredArgsConstructor
Expand All @@ -25,24 +26,29 @@ public class JwtFilter extends OncePerRequestFilter {

@Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain)
throws ServletException, IOException {
String jwt = resolveToken(request);
Optional<String> jwt = resolveToken(request);

jwt.ifPresent(this::setAuthentication);

if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
Authentication authentication = tokenProvider.getAuthentication(jwt);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(request, response);
}

private String resolveToken(HttpServletRequest request) {
private void setAuthentication(final String token) {
if (tokenProvider.validateToken(token)) {
Optional<Authentication> authentication = tokenProvider.getAuthentication(token);
authentication.ifPresent(SecurityContextHolder.getContext()::setAuthentication);
}
}

private Optional<String> resolveToken(final HttpServletRequest request) {
String bearerToken = request.getHeader(AUTHORIZATION_HEADER);

if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(BEARER_PREFIX)) {
return bearerToken.substring(7);
return Optional.of(bearerToken.substring(BEARER_PREFIX.length()));
}

return null;
return Optional.empty();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.twtw.backend.config.security.jwt;

import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.security.Key;

@Configuration
public class KeyConfig {

@Bean
public Key key(@Value("${jwt.secret}") final String secretKey) {
byte[] keyBytes = Decoders.BASE64.decode(secretKey);
return Keys.hmacShaKeyFor(keyBytes);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,29 @@

import com.twtw.backend.domain.member.dto.response.TokenDto;
import com.twtw.backend.domain.member.entity.Member;
import com.twtw.backend.domain.member.entity.Role;
import com.twtw.backend.global.exception.AuthorityException;

import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

import java.security.Key;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;

@Component
public class TokenProvider implements InitializingBean {
@RequiredArgsConstructor
public class TokenProvider {

private Key key;
private final String secretKey;
private final Key key;
private static final String AUTHORITIES_KEY = "auth";
private static final Long ACCESS_TOKEN_EXPIRE_LENGTH = 60L * 60 * 24 * 1000; // 1 Day
private static final Long REFRESH_TOKEN_EXPIRE_LENGTH = 60L * 60 * 24 * 14 * 1000; // 14 Days

public TokenProvider(@Value("${jwt.secret}") String secretKey) {
this.secretKey = secretKey;
}

@Override
public void afterPropertiesSet() throws Exception {
byte[] keyBytes = Decoders.BASE64.decode(secretKey);
this.key = Keys.hmacShaKeyFor(keyBytes);
}

public TokenDto createToken(Authentication authentication) {
String authorities =
authentication.getAuthorities().stream()
Expand Down Expand Up @@ -69,23 +52,30 @@ public TokenDto createToken(Authentication authentication) {
return new TokenDto(accessToken, refreshToken);
}

public Authentication getAuthentication(String accessToken) {
public Optional<Authentication> getAuthentication(String accessToken) {
Claims claims = parseClaims(accessToken);

if (claims.get(AUTHORITIES_KEY) == null) {
throw new AuthorityException();
}
return Optional.ofNullable(claims.get(AUTHORITIES_KEY))
.map(
auth -> {
Collection<GrantedAuthority> authorities = new ArrayList<>();
String role = claims.get(AUTHORITIES_KEY).toString();

Collection<GrantedAuthority> authorities = new ArrayList<>();
String role = claims.get(AUTHORITIES_KEY).toString();
addRole(role, authorities);

if (role.equals("ROLE_ADMIN")) {
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
} else if (role.equals("ROLE_USER")) {
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
}
return new UsernamePasswordAuthenticationToken(claims.getSubject(), "", authorities);
}
);
}

return new UsernamePasswordAuthenticationToken(claims.getSubject(), "", authorities);
private void addRole(final String role, final Collection<GrantedAuthority> authorities) {
if (role.equals(Role.ROLE_ADMIN.name())) {
authorities.add(new SimpleGrantedAuthority(Role.ROLE_ADMIN.name()));
return;
}
if (role.equals(Role.ROLE_USER.name())) {
authorities.add(new SimpleGrantedAuthority(Role.ROLE_USER.name()));
}
}

public boolean validateToken(String token) {
Expand All @@ -102,24 +92,19 @@ public boolean validateToken(String token) {

private Claims parseClaims(String accessToken) {
try {
Claims claims =
Jwts.parserBuilder()
return Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(accessToken)
.getBody();
return claims;
} catch (ExpiredJwtException e) {
return e.getClaims();
throw new AuthorityException();
}
}

public UsernamePasswordAuthenticationToken makeCredit(Member member) {
List<GrantedAuthority> role = new ArrayList<>();
role.add(new SimpleGrantedAuthority(member.getRole().toString()));
UsernamePasswordAuthenticationToken credit =
new UsernamePasswordAuthenticationToken(member.getId().toString(), "", role);
List<GrantedAuthority> role = List.of(new SimpleGrantedAuthority(member.getRole().toString()));

return credit;
return new UsernamePasswordAuthenticationToken(member.getId().toString(), "", role);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@
@Builder
@AllArgsConstructor
public class AfterLoginResponse {

private static final AfterLoginResponse SIGNUP = AfterLoginResponse.builder()
.status(AuthStatus.SIGNUP).build();
private AuthStatus status;
private TokenDto tokenDto;

public static AfterLoginResponse ofSignup() {
return SIGNUP;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.twtw.backend.domain.member.mapper.MemberMapper;
import com.twtw.backend.domain.member.repository.MemberRepository;
import com.twtw.backend.domain.member.repository.RefreshTokenRepository;
import com.twtw.backend.global.exception.AuthorityException;
import com.twtw.backend.global.exception.EntityNotFoundException;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
Expand Down Expand Up @@ -86,14 +87,14 @@ public AfterLoginResponse getTokenByOAuth(OAuthRequest request) {
Optional<Member> member =
memberRepository.findByOAuthIdAndAuthType(clientId, request.getAuthType());

if (member.isPresent()) {
Member curMember = member.get();
UsernamePasswordAuthenticationToken credit = tokenProvider.makeCredit(curMember);
TokenDto tokenDto = saveRefreshToken(credit, curMember.getId().toString());
return new AfterLoginResponse(AuthStatus.SIGNIN, tokenDto);
}
return member.map(this::getAfterLoginResponse)
.orElseGet(AfterLoginResponse::ofSignup);
}

return new AfterLoginResponse(AuthStatus.SIGNUP, null);
private AfterLoginResponse getAfterLoginResponse(final Member member) {
UsernamePasswordAuthenticationToken credit = tokenProvider.makeCredit(member);
TokenDto tokenDto = saveRefreshToken(credit, member.getId().toString());
return new AfterLoginResponse(AuthStatus.SIGNIN, tokenDto);
}

/*
Expand All @@ -109,16 +110,19 @@ public TokenDto refreshToken(TokenRequest tokenRequest) {
throw new RefreshTokenValidationException();
}

Authentication authentication =
Optional<Authentication> authentication =
tokenProvider.getAuthentication(tokenRequest.getAccessToken());

String userName = authentication.getName();
return authentication.map(auth -> getTokenDto(auth, refreshToken))
.orElseThrow(AuthorityException::new);
}

private TokenDto getTokenDto(final Authentication auth, final String refreshToken) {
String userName = auth.getName();
if (!getRefreshTokenValue(userName).equals(refreshToken)) {
throw new RefreshTokenInfoMismatchException();
}

return saveRefreshToken(authentication, userName);
return saveRefreshToken(auth, auth.getName());
}

public String getRefreshTokenValue(String tokenKey) {
Expand Down

0 comments on commit 600acd3

Please sign in to comment.