29. JWT토큰 서버 구축 완료
by 볼빵빵오춘기JwtAuthorizationFilter.java - 생성 및 코드 작성
- config > jwt 밑에 JwtAuthorizationFilter.java 생성한다.
- BasicAuthenticationFilter extends 해준다.
- 시큐리티가 filter를 가지고 있는데 그 필터중에 BasicAuthenticationFilter 라는 것이 있다.
- 권한이나 인증이 필요한 특정 주소를 요청했을 때 위 필터를 무조건 타게 되어있다.
- 만약에 권한이 인증이 필요한 주소가 아니라면 이 필터를 안탄다.
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {
// constructor 가 없어 error가 나므로 constructor 생성
public JwtAuthorizationFilter(AuthenticationManager authenticationManager, UserRepository userRepository) {
super(authenticationManager);
System.out.println("인증이나 권한이 필요한 주소가 요청이 됨.");
}
}
SecurityConfig.java - configure()코드 추가
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilter(corsFilter) // @CrossOrigin(인증x), 시큐리티 필터에 등록(인증o)
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.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')")
.antMatchers("/api/v1/manager/**")
.access("hasRole('ROLE_MANAGER') or hasRole('ROLE_ADMIN')")
.antMatchers("/api/v1/admin/**")
.access("hasRole('ROLE_ADMIN')")
.anyRequest().permitAll();
}
JwtAuthorizationFilter.java - doFilterInternal() 코드 작성
코드 작성1
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {
public JwtAuthorizationFilter(AuthenticationManager authenticationManager) {
super(authenticationManager);
}
// 인증이나 권한이 필요한 주소요청이 있을 때 해당 필터를 타게 된다.
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
super.doFilterInternal(request,response,chain)
System.out.println("인증이나 권한이 필요한 주소가 요청이 됨.");
}
}
코드 작성2
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {
public JwtAuthorizationFilter(AuthenticationManager authenticationManager) {
super(authenticationManager);
}
// 인증이나 권한이 필요한 주소요청이 있을 때 해당 필터를 타게 된다.
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
// super.doFilterInternal(request, response, chain);
System.out.println("인증이나 권한이 필요한 주소가 요청이 됨.");
String jwtHeader = request.getHeader("Authorization");
System.out.println("jwtHeader : "+jwtHeader);
}
}
코드작성3
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("인증이나 권한이 필요한 주소가 요청이 됨.");
String jwtHeader = request.getHeader("Authorization");
System.out.println("jwtHeader : "+jwtHeader);
// header가 있는지 확인
if(jwtHeader == null|| !jwtHeader.startsWith("Bearer")){
chain.doFilter(request,response);
return; //
}
// JWT 토큰을 검증을 해서 정상적인 사용자인지 확인
String jwtToken = request.getHeader("Authorization").replace("Bearer ","");
String username = JWT.require(Algorithm.HMAC512("cos")).build().verify(jwtToken)
.getClaim("username").asString();
// 서명이 정상적으로 됐다면
if(username!=null){
}
}
}
SecurityConfig.java - UserRepository 타입 변수 선언 및 configure() - addFilter()에 파라미터 추가
@Override
protected void configure(HttpSecurity http) throws Exception {
// http.addFilter(new MyFilter1()); // 에러
// http.addFilterBefore(new MyFilter1(), BasicAuthenticationFilter.class); // 필터가 실행되는지 test
// http.addFilterBefore(new MyFilter3(), BasicAuthenticationFilter.class); // 필터1,2를 만들로 FilterConfig에서 만든 후 Security 필터가 먼저 실행되는지 아니면 내가 만든 필터가 먼저 실행되는지 test
http
.addFilter(corsFilter) // @CrossOrigin(인증x), 시큐리티 필터에 등록(인증o)
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.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')")
.antMatchers("/api/v1/manager/**")
.access("hasRole('ROLE_MANAGER') or hasRole('ROLE_ADMIN')")
.antMatchers("/api/v1/admin/**")
.access("hasRole('ROLE_ADMIN')")
.anyRequest().permitAll();
}
}
JwtAuthorizationFilter.java - 생성자에 파라미터 추가
private UserRepository userRepository;
public JwtAuthorizationFilter(AuthenticationManager authenticationManager, UserRepository userRepository) {
super(authenticationManager);
this.userRepository = userRepository;
}
JwtAuthorizationFilter.java - doFilterInternal() 에서 서명이 정상일 때 부분에 코드 추가
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
// super.doFilterInternal(request, response, chain);
System.out.println("인증이나 권한이 필요한 주소가 요청이 됨.");
String jwtHeader = request.getHeader("Authorization");
System.out.println("jwtHeader : "+jwtHeader);
// header가 있는지 확인
if(jwtHeader == null|| !jwtHeader.startsWith("Bearer")){
chain.doFilter(request,response);
return;
}
// JWT 토큰을 검증을 해서 정상적인 사용자인지 확인
String jwtToken = request.getHeader("Authorization").replace("Bearer ","");
String username = JWT.require(Algorithm.HMAC512("cos")).build().verify(jwtToken)
.getClaim("username").asString();
// 서명이 정상적으로 됐다면
if(username!=null){
System.out.println("username 정상");
User userEntity = userRepository.findByUsername(username); // 정상적으로 select가 되면 정상적인 사용자
PrincipalDetails principalDetails = new PrincipalDetails(userEntity);
// JWT 토큰 서명을 통해서 서명이 정상이면 Authentication 객체를 만들어 준다.
Authentication authentication = new UsernamePasswordAuthenticationToken(principalDetails,null,principalDetails.getAuthorities());
// 강제로 시큐리티의 세션에 접근하여 Authentication 객체를 저장
SecurityContextHolder.getContext().setAuthentication(authentication);
}
chain.doFilter(request,response);
}
RestApiController.java - 테스트를 위한 요청 주소 추가
// user, manager, admin 권한만 접근 가능
@GetMapping("/api/v1/user")
public String user(Authentication authentication){
PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
System.out.println("user() authentication : "+principalDetails.getUsername());
return "user";
}
// ]manager, admin 권한만 접근 가능
@GetMapping("/api/v1/manager")
public String manager(){
return "manager";
}
// admin 권한만 접근 가능
@GetMapping("/api/v1/admin")
public String admin(){
return "admin";
}
추가적으로 JwtProperties.java 생성 및 코드 추가
public interface JwtProperties {
String SECRET = "cos"; // 우리 서버만 알고 있는 비밀값
int EXPIRATION_TIME = 864000000; // 10일 (1/1000초)
String TOKEN_PREFIX = "Bearer ";
String HEADER_STRING = "Authorization";
}
'강의 따라하기 > JWT' 카테고리의 다른 글
28. JWT 토큰 만들어서 응답하기 (0) | 2024.08.25 |
---|---|
27. JWT를 위한 강제 로그인 진행 (0) | 2024.08.25 |
26. 회원가입 로직 누락 (0) | 2024.08.25 |
25. JWT를 위한 로그인 시도 (0) | 2024.08.25 |
24. JWT 임시 토큰 만들어서 테스트 해보기 (0) | 2024.08.25 |
블로그의 정보
Hello 춘기's world
볼빵빵오춘기