Skip to content

Commit 600acd3

Browse files
authored
Merge pull request #92 from HongDam-org/feat/refactor-security-member
[REFACTOR] 멤버 및 시큐리티 리팩토링
2 parents 8fb851e + fa3b5e7 commit 600acd3

File tree

6 files changed

+94
-72
lines changed

6 files changed

+94
-72
lines changed

backend/src/main/java/com/twtw/backend/config/security/SecurityConfig.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@
1818
@EnableWebSecurity
1919
@RequiredArgsConstructor
2020
public class SecurityConfig {
21+
22+
private static final String[] AUTH_WHITELIST = {
23+
"/auth/refresh",
24+
"/auth/save",
25+
"/auth/login",
26+
"/member/duplicate/**",
27+
"/location/**",
28+
"/actuator/**"};
2129
private final JwtFilter jwtFilter;
2230
private final JwtAccessDeniedHandler jwtAccessDeniedHandler;
2331
private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@@ -30,14 +38,7 @@ public SecurityFilterChain configure(HttpSecurity http) throws Exception {
3038
.formLogin(f -> f.disable())
3139
.authorizeHttpRequests(
3240
x ->
33-
x.requestMatchers(
34-
"/auth/refresh",
35-
"/auth/save",
36-
"/auth/login",
37-
"/member/duplicate/**",
38-
"/location/**",
39-
"/actuator/**",
40-
"/member/test/**")
41+
x.requestMatchers(AUTH_WHITELIST)
4142
.permitAll()
4243
.anyRequest()
4344
.authenticated())

backend/src/main/java/com/twtw/backend/config/security/jwt/JwtFilter.java

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.springframework.web.filter.OncePerRequestFilter;
1515

1616
import java.io.IOException;
17+
import java.util.Optional;
1718

1819
@Component
1920
@RequiredArgsConstructor
@@ -25,24 +26,29 @@ public class JwtFilter extends OncePerRequestFilter {
2526

2627
@Override
2728
protected void doFilterInternal(
28-
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
29+
final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain)
2930
throws ServletException, IOException {
30-
String jwt = resolveToken(request);
31+
Optional<String> jwt = resolveToken(request);
32+
33+
jwt.ifPresent(this::setAuthentication);
3134

32-
if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
33-
Authentication authentication = tokenProvider.getAuthentication(jwt);
34-
SecurityContextHolder.getContext().setAuthentication(authentication);
35-
}
3635
filterChain.doFilter(request, response);
3736
}
3837

39-
private String resolveToken(HttpServletRequest request) {
38+
private void setAuthentication(final String token) {
39+
if (tokenProvider.validateToken(token)) {
40+
Optional<Authentication> authentication = tokenProvider.getAuthentication(token);
41+
authentication.ifPresent(SecurityContextHolder.getContext()::setAuthentication);
42+
}
43+
}
44+
45+
private Optional<String> resolveToken(final HttpServletRequest request) {
4046
String bearerToken = request.getHeader(AUTHORIZATION_HEADER);
4147

4248
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(BEARER_PREFIX)) {
43-
return bearerToken.substring(7);
49+
return Optional.of(bearerToken.substring(BEARER_PREFIX.length()));
4450
}
4551

46-
return null;
52+
return Optional.empty();
4753
}
4854
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.twtw.backend.config.security.jwt;
2+
3+
import io.jsonwebtoken.io.Decoders;
4+
import io.jsonwebtoken.security.Keys;
5+
import org.springframework.beans.factory.annotation.Value;
6+
import org.springframework.context.annotation.Bean;
7+
import org.springframework.context.annotation.Configuration;
8+
9+
import java.security.Key;
10+
11+
@Configuration
12+
public class KeyConfig {
13+
14+
@Bean
15+
public Key key(@Value("${jwt.secret}") final String secretKey) {
16+
byte[] keyBytes = Decoders.BASE64.decode(secretKey);
17+
return Keys.hmacShaKeyFor(keyBytes);
18+
}
19+
}

backend/src/main/java/com/twtw/backend/config/security/jwt/TokenProvider.java

Lines changed: 29 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,46 +2,29 @@
22

33
import com.twtw.backend.domain.member.dto.response.TokenDto;
44
import com.twtw.backend.domain.member.entity.Member;
5+
import com.twtw.backend.domain.member.entity.Role;
56
import com.twtw.backend.global.exception.AuthorityException;
6-
77
import io.jsonwebtoken.*;
8-
import io.jsonwebtoken.io.Decoders;
9-
import io.jsonwebtoken.security.Keys;
10-
11-
import org.springframework.beans.factory.InitializingBean;
12-
import org.springframework.beans.factory.annotation.Value;
8+
import lombok.RequiredArgsConstructor;
139
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
1410
import org.springframework.security.core.Authentication;
1511
import org.springframework.security.core.GrantedAuthority;
1612
import org.springframework.security.core.authority.SimpleGrantedAuthority;
1713
import org.springframework.stereotype.Component;
1814

1915
import java.security.Key;
20-
import java.util.ArrayList;
21-
import java.util.Collection;
22-
import java.util.Date;
23-
import java.util.List;
16+
import java.util.*;
2417
import java.util.stream.Collectors;
2518

2619
@Component
27-
public class TokenProvider implements InitializingBean {
20+
@RequiredArgsConstructor
21+
public class TokenProvider {
2822

29-
private Key key;
30-
private final String secretKey;
23+
private final Key key;
3124
private static final String AUTHORITIES_KEY = "auth";
3225
private static final Long ACCESS_TOKEN_EXPIRE_LENGTH = 60L * 60 * 24 * 1000; // 1 Day
3326
private static final Long REFRESH_TOKEN_EXPIRE_LENGTH = 60L * 60 * 24 * 14 * 1000; // 14 Days
3427

35-
public TokenProvider(@Value("${jwt.secret}") String secretKey) {
36-
this.secretKey = secretKey;
37-
}
38-
39-
@Override
40-
public void afterPropertiesSet() throws Exception {
41-
byte[] keyBytes = Decoders.BASE64.decode(secretKey);
42-
this.key = Keys.hmacShaKeyFor(keyBytes);
43-
}
44-
4528
public TokenDto createToken(Authentication authentication) {
4629
String authorities =
4730
authentication.getAuthorities().stream()
@@ -69,23 +52,30 @@ public TokenDto createToken(Authentication authentication) {
6952
return new TokenDto(accessToken, refreshToken);
7053
}
7154

72-
public Authentication getAuthentication(String accessToken) {
55+
public Optional<Authentication> getAuthentication(String accessToken) {
7356
Claims claims = parseClaims(accessToken);
7457

75-
if (claims.get(AUTHORITIES_KEY) == null) {
76-
throw new AuthorityException();
77-
}
58+
return Optional.ofNullable(claims.get(AUTHORITIES_KEY))
59+
.map(
60+
auth -> {
61+
Collection<GrantedAuthority> authorities = new ArrayList<>();
62+
String role = claims.get(AUTHORITIES_KEY).toString();
7863

79-
Collection<GrantedAuthority> authorities = new ArrayList<>();
80-
String role = claims.get(AUTHORITIES_KEY).toString();
64+
addRole(role, authorities);
8165

82-
if (role.equals("ROLE_ADMIN")) {
83-
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
84-
} else if (role.equals("ROLE_USER")) {
85-
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
86-
}
66+
return new UsernamePasswordAuthenticationToken(claims.getSubject(), "", authorities);
67+
}
68+
);
69+
}
8770

88-
return new UsernamePasswordAuthenticationToken(claims.getSubject(), "", authorities);
71+
private void addRole(final String role, final Collection<GrantedAuthority> authorities) {
72+
if (role.equals(Role.ROLE_ADMIN.name())) {
73+
authorities.add(new SimpleGrantedAuthority(Role.ROLE_ADMIN.name()));
74+
return;
75+
}
76+
if (role.equals(Role.ROLE_USER.name())) {
77+
authorities.add(new SimpleGrantedAuthority(Role.ROLE_USER.name()));
78+
}
8979
}
9080

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

10393
private Claims parseClaims(String accessToken) {
10494
try {
105-
Claims claims =
106-
Jwts.parserBuilder()
95+
return Jwts.parserBuilder()
10796
.setSigningKey(key)
10897
.build()
10998
.parseClaimsJws(accessToken)
11099
.getBody();
111-
return claims;
112100
} catch (ExpiredJwtException e) {
113-
return e.getClaims();
101+
throw new AuthorityException();
114102
}
115103
}
116104

117105
public UsernamePasswordAuthenticationToken makeCredit(Member member) {
118-
List<GrantedAuthority> role = new ArrayList<>();
119-
role.add(new SimpleGrantedAuthority(member.getRole().toString()));
120-
UsernamePasswordAuthenticationToken credit =
121-
new UsernamePasswordAuthenticationToken(member.getId().toString(), "", role);
106+
List<GrantedAuthority> role = List.of(new SimpleGrantedAuthority(member.getRole().toString()));
122107

123-
return credit;
108+
return new UsernamePasswordAuthenticationToken(member.getId().toString(), "", role);
124109
}
125110
}

backend/src/main/java/com/twtw/backend/domain/member/dto/response/AfterLoginResponse.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@
1010
@Builder
1111
@AllArgsConstructor
1212
public class AfterLoginResponse {
13+
14+
private static final AfterLoginResponse SIGNUP = AfterLoginResponse.builder()
15+
.status(AuthStatus.SIGNUP).build();
1316
private AuthStatus status;
1417
private TokenDto tokenDto;
18+
19+
public static AfterLoginResponse ofSignup() {
20+
return SIGNUP;
21+
}
1522
}

backend/src/main/java/com/twtw/backend/domain/member/service/AuthService.java

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import com.twtw.backend.domain.member.mapper.MemberMapper;
1818
import com.twtw.backend.domain.member.repository.MemberRepository;
1919
import com.twtw.backend.domain.member.repository.RefreshTokenRepository;
20+
import com.twtw.backend.global.exception.AuthorityException;
2021
import com.twtw.backend.global.exception.EntityNotFoundException;
2122

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

89-
if (member.isPresent()) {
90-
Member curMember = member.get();
91-
UsernamePasswordAuthenticationToken credit = tokenProvider.makeCredit(curMember);
92-
TokenDto tokenDto = saveRefreshToken(credit, curMember.getId().toString());
93-
return new AfterLoginResponse(AuthStatus.SIGNIN, tokenDto);
94-
}
90+
return member.map(this::getAfterLoginResponse)
91+
.orElseGet(AfterLoginResponse::ofSignup);
92+
}
9593

96-
return new AfterLoginResponse(AuthStatus.SIGNUP, null);
94+
private AfterLoginResponse getAfterLoginResponse(final Member member) {
95+
UsernamePasswordAuthenticationToken credit = tokenProvider.makeCredit(member);
96+
TokenDto tokenDto = saveRefreshToken(credit, member.getId().toString());
97+
return new AfterLoginResponse(AuthStatus.SIGNIN, tokenDto);
9798
}
9899

99100
/*
@@ -109,16 +110,19 @@ public TokenDto refreshToken(TokenRequest tokenRequest) {
109110
throw new RefreshTokenValidationException();
110111
}
111112

112-
Authentication authentication =
113+
Optional<Authentication> authentication =
113114
tokenProvider.getAuthentication(tokenRequest.getAccessToken());
114115

115-
String userName = authentication.getName();
116+
return authentication.map(auth -> getTokenDto(auth, refreshToken))
117+
.orElseThrow(AuthorityException::new);
118+
}
116119

120+
private TokenDto getTokenDto(final Authentication auth, final String refreshToken) {
121+
String userName = auth.getName();
117122
if (!getRefreshTokenValue(userName).equals(refreshToken)) {
118123
throw new RefreshTokenInfoMismatchException();
119124
}
120-
121-
return saveRefreshToken(authentication, userName);
125+
return saveRefreshToken(auth, auth.getName());
122126
}
123127

124128
public String getRefreshTokenValue(String tokenKey) {

0 commit comments

Comments
 (0)