Copy & Paste, Struggling
This commit is contained in:
@@ -49,13 +49,17 @@ dependencies {
|
|||||||
/*
|
/*
|
||||||
Security
|
Security
|
||||||
*/
|
*/
|
||||||
// implementation 'org.springframework.boot:spring-boot-starter-security:2.6.7'
|
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-security:2.7.0'
|
implementation 'org.springframework.boot:spring-boot-starter-security:2.7.0'
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Validation
|
Validation
|
||||||
*/
|
*/
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-validation'
|
implementation 'org.springframework.boot:spring-boot-starter-validation'
|
||||||
|
|
||||||
|
/*
|
||||||
|
Jwt (JSON Web Token Support For The JVM)
|
||||||
|
*/
|
||||||
|
implementation 'io.jsonwebtoken:jjwt:0.9.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.named('test') {
|
tasks.named('test') {
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public class SecurityConfig {
|
|||||||
.authorizeRequests()
|
.authorizeRequests()
|
||||||
.antMatchers("/", "/user/signUp", "/user/userList", "/user/signIn*").permitAll()
|
.antMatchers("/", "/user/signUp", "/user/userList", "/user/signIn*").permitAll()
|
||||||
.anyRequest().authenticated();
|
.anyRequest().authenticated();
|
||||||
|
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
42
src/main/java/demo/api/jwt/JwtTokenFilter.java
Normal file
42
src/main/java/demo/api/jwt/JwtTokenFilter.java
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package demo.api.jwt;
|
||||||
|
|
||||||
|
import demo.api.jwt.exception.CustomException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
// Request 이전에 1회 작동할 필터
|
||||||
|
public class JwtTokenFilter extends OncePerRequestFilter {
|
||||||
|
private JwtTokenProvider jwtTokenProvider;
|
||||||
|
|
||||||
|
public JwtTokenFilter(JwtTokenProvider jwtTokenProvider) {
|
||||||
|
this.jwtTokenProvider = jwtTokenProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(
|
||||||
|
HttpServletRequest request,
|
||||||
|
HttpServletResponse response,
|
||||||
|
FilterChain filterChain
|
||||||
|
) throws ServletException, IOException {
|
||||||
|
String token = jwtTokenProvider.resolveToken(request);
|
||||||
|
try {
|
||||||
|
if (token != null && jwtTokenProvider.validateToken(token)) {
|
||||||
|
Authentication auth = jwtTokenProvider.getAuthentication(token);
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||||
|
}
|
||||||
|
} catch (CustomException ex) {
|
||||||
|
//this is very important, since it guarantees the user is not authenticated at all
|
||||||
|
SecurityContextHolder.clearContext();
|
||||||
|
response.sendError(ex.getHttpStatus().value(), ex.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
84
src/main/java/demo/api/jwt/JwtTokenProvider.java
Normal file
84
src/main/java/demo/api/jwt/JwtTokenProvider.java
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package demo.api.jwt;
|
||||||
|
|
||||||
|
import demo.api.jwt.exception.CustomException;
|
||||||
|
import io.jsonwebtoken.Claims;
|
||||||
|
import io.jsonwebtoken.ExpiredJwtException;
|
||||||
|
import io.jsonwebtoken.JwtException;
|
||||||
|
import io.jsonwebtoken.Jwts;
|
||||||
|
import io.jsonwebtoken.MalformedJwtException;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.Date;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
|
// 유저 정보로 JWT 토큰을 만들거나 토큰을 바탕으로 유저 정보를 가져옴
|
||||||
|
@Component
|
||||||
|
public class JwtTokenProvider {
|
||||||
|
/**
|
||||||
|
* THIS IS NOT A SECURE PRACTICE! For simplicity, we are storing a static key here. Ideally, in a
|
||||||
|
* microservices environment, this key would be kept on a config-server.
|
||||||
|
*/
|
||||||
|
@Value("${jwt.token.open-secret-key}")
|
||||||
|
private String secret_key;
|
||||||
|
|
||||||
|
@Value("${jwt.token.expire-length}")
|
||||||
|
private long expire_time;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserDetailsService userDetailsService;
|
||||||
|
|
||||||
|
@PostConstruct // 의존성 주입이 이루어진 후 초기화를 수행
|
||||||
|
protected void init() {
|
||||||
|
secret_key = Base64.getEncoder().encodeToString(secret_key.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String createToken(String username, List<AppUserRole> appUserRoles) {
|
||||||
|
|
||||||
|
Claims claims = Jwts.claims().setSubject(username);
|
||||||
|
claims.put("auth", appUserRoles.stream().map(s -> new SimpleGrantedAuthority(s.getAuthority())).filter(Objects::nonNull).collect(Collectors.toList()));
|
||||||
|
|
||||||
|
Date now = new Date();
|
||||||
|
Date validity = new Date(now.getTime() + expire_time);
|
||||||
|
|
||||||
|
return Jwts.builder()
|
||||||
|
.setClaims(claims)
|
||||||
|
.setIssuedAt(now)
|
||||||
|
.setExpiration(validity)
|
||||||
|
.signWith(SignatureAlgorithm.HS256, secret_key)
|
||||||
|
.compact();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Authentication getAuthentication(String token) {
|
||||||
|
UserDetails userDetails = userDetailsService.loadUserByUsername(getUsername(token));
|
||||||
|
return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername(String token) {
|
||||||
|
return Jwts.parser().setSigningKey(secret_key).parseClaimsJws(token).getBody().getSubject();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String resolveToken(HttpServletRequest req) {
|
||||||
|
String bearerToken = req.getHeader("Authorization");
|
||||||
|
if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
|
||||||
|
return bearerToken.substring(7);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean validateToken(String token) {
|
||||||
|
try {
|
||||||
|
Jwts.parser().setSigningKey(secret_key).parseClaimsJws(token);
|
||||||
|
return true;
|
||||||
|
} catch (JwtException e) {
|
||||||
|
// MalformedJwtException | ExpiredJwtException | IllegalArgumentException
|
||||||
|
throw new CustomException("Error on Token", HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/main/java/demo/api/jwt/exception/CustomException.java
Normal file
26
src/main/java/demo/api/jwt/exception/CustomException.java
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package demo.api.jwt.exception;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
|
public class CustomException extends RuntimeException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final String message;
|
||||||
|
private final HttpStatus httpStatus;
|
||||||
|
|
||||||
|
public CustomException(String message, HttpStatus httpStatus) {
|
||||||
|
this.message = message;
|
||||||
|
this.httpStatus = httpStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpStatus getHttpStatus() {
|
||||||
|
return httpStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -8,4 +8,8 @@ spring:
|
|||||||
jpa:
|
jpa:
|
||||||
show-sql: true
|
show-sql: true
|
||||||
hibernate:
|
hibernate:
|
||||||
ddl-auto: none
|
ddl-auto: none
|
||||||
|
jwt:
|
||||||
|
token:
|
||||||
|
secret-key: open-secret-key
|
||||||
|
expire-length: 300000
|
||||||
Reference in New Issue
Block a user