Authorization Authentication with JWT

This commit is contained in:
haerong22
2020-12-15 20:24:42 +09:00
parent db7e525672
commit c0bab54b70
7 changed files with 103 additions and 8 deletions

View File

@@ -1,6 +1,8 @@
package com.security.jwt.config;
import com.security.jwt.jwt.JwtAuthenticationFilter;
import com.security.jwt.config.jwt.JwtAuthenticationFilter;
import com.security.jwt.config.jwt.JwtAuthorizationFilter;
import com.security.jwt.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -17,6 +19,7 @@ import org.springframework.web.filter.CorsFilter;
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final CorsFilter corsFilter;
private final UserRepository userRepository;
@Bean
public BCryptPasswordEncoder passwordEncoder() {
@@ -33,6 +36,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
.formLogin().disable()
.httpBasic().disable()
.addFilter(new JwtAuthenticationFilter(authenticationManager())) // AuthenticationManager
.addFilter(new JwtAuthorizationFilter(authenticationManager(), userRepository))
.authorizeRequests()
.antMatchers("/api/v1/user/**")
.access("hasRole('ROLE_USER') or hasRole('ROLE_MANAGER') or hasRole('ROLE_ADMIN')")

View File

@@ -1,4 +1,4 @@
package com.security.jwt.auth;
package com.security.jwt.config.auth;
import com.security.jwt.model.User;
import lombok.Data;

View File

@@ -1,4 +1,4 @@
package com.security.jwt.auth;
package com.security.jwt.config.auth;
import com.security.jwt.model.User;
import com.security.jwt.repository.UserRepository;

View File

@@ -1,9 +1,9 @@
package com.security.jwt.jwt;
package com.security.jwt.config.jwt;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.security.jwt.auth.PrincipalDetails;
import com.security.jwt.config.auth.PrincipalDetails;
import com.security.jwt.model.User;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager;
@@ -84,11 +84,11 @@ public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilte
// RSA방식이 아닌 HASH 방식 (secret key 필요 )
String jwtToken = JWT.create()
.withSubject("wj토큰")
.withExpiresAt(new Date(System.currentTimeMillis()+(60000 * 10)))
.withExpiresAt(new Date(System.currentTimeMillis()+JwtProperties.EXPIRATION_TIME))
.withClaim("id", principalDetails.getUser().getId())
.withClaim("username", principalDetails.getUser().getUsername())
.sign(Algorithm.HMAC512("wj"));
.sign(Algorithm.HMAC512(JwtProperties.SECRET));
response.addHeader("Authorization", "Bearer " + jwtToken);
response.addHeader(JwtProperties.HEADER_STRING, JwtProperties.TOKEN_PREFIX + jwtToken);
}
}

View File

@@ -0,0 +1,65 @@
package com.security.jwt.config.jwt;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.security.jwt.config.auth.PrincipalDetails;
import com.security.jwt.model.User;
import com.security.jwt.repository.UserRepository;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
// 시큐리티가 가지고 있는 BasicAuthenticationFilter 는
// 권한이나 인증이 필요한 특정 주소를 요청 했을 때 필터를 거치게 되고
// 만약 권한, 인증이 필요없는 주소면 필터를 거치지 않는다.
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {
private UserRepository userRepository;
public JwtAuthorizationFilter(AuthenticationManager authenticationManager, UserRepository userRepository) {
super(authenticationManager);
this.userRepository = userRepository;
}
// 인증이나 권한이 필요한 주소 요청이 있을 때 해당 필터를 거친다.
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
// super.doFilterInternal(request, response, chain);
System.out.println("인증이나 권한이 필요한 주소 요청 : JwtAuthorizationFilter ");
String jwtHeader = request.getHeader(JwtProperties.HEADER_STRING);
System.out.println("jwtHeader " + jwtHeader);
// jwtHeader가 있는지 확인
if(jwtHeader == null || !jwtHeader.startsWith(JwtProperties.TOKEN_PREFIX)) {
chain.doFilter(request, response);
return;
}
// jwt token 검증
String jwtToken = request.getHeader(JwtProperties.HEADER_STRING).replace(JwtProperties.TOKEN_PREFIX,"");
String username =
JWT.require(Algorithm.HMAC512(JwtProperties.SECRET)).build().verify(jwtToken).getClaim("username").asString();
// 서명이 정상적으로 완료
if(username != null) {
User userEntity = userRepository.findByUsername(username);
PrincipalDetails principalDetails = new PrincipalDetails(userEntity);
// jwt token 서명이 정상이면 Authentication 객체를 만들어 준다.
Authentication authentication =
new UsernamePasswordAuthenticationToken(principalDetails, null, principalDetails.getAuthorities());
// 강제로 시큐리티의 세션에 접근하여 Authentication 객체를 저장
SecurityContextHolder.getContext().setAuthentication(authentication);
}
chain.doFilter(request, response);
}
}

View File

@@ -0,0 +1,8 @@
package com.security.jwt.config.jwt;
public interface JwtProperties {
String SECRET = "wj";
int EXPIRATION_TIME = 60000*10;
String TOKEN_PREFIX = "Bearer ";
String HEADER_STRING = "Authorization";
}

View File

@@ -33,4 +33,22 @@ public class RestApiController {
userRepository.save(user);
return "회원가입완료";
}
// user, manager, admin 접근 가능
@GetMapping("/api/v1/user")
public String user() {
return "user";
}
// manager, admin 접근가능
@GetMapping("/api/v1/manager")
public String manager() {
return "manager";
}
// admin 접근가능
@GetMapping("/api/v1/admin")
public String admin() {
return "admin";
}
}