jwt filter

This commit is contained in:
kim
2020-12-15 02:38:24 +09:00
parent 4a59fe9c1b
commit 8e90d6b380
10 changed files with 212 additions and 22 deletions

27
codingtest/src/Test.java Normal file
View File

@@ -0,0 +1,27 @@
public class Test {
public static void main(String[] args) {
System.out.println(solution("ABABAAAAABA"));
}
public static int solution(String name) {
int len = name.length();
int move = len-1;
int answer = 0 ;
for(int i=0; i<len; ++i) {
answer += Math.min(name.charAt(i) - 'A', 91 - name.charAt(i));
int next = i+1;
while(next<len && name.charAt(next)=='A') {
++next;
}
move = Math.min(move,i+len-next+Math.min(i,len-next));
}
answer += move;
return answer;
}
}

View File

@@ -0,0 +1,57 @@
package com.security.jwt.auth;
import com.security.jwt.model.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
import java.util.Collection;
public class PrincipalDetails implements UserDetails {
private User user;
public PrincipalDetails(User user) {
this.user = user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new ArrayList<>();
user.getRoleList().forEach(r -> {
authorities.add(() -> r);
});
return authorities;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}

View File

@@ -0,0 +1,26 @@
package com.security.jwt.auth;
import com.security.jwt.model.User;
import com.security.jwt.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
// http://localhost:8080/login
// -> 스프링 시큐리티 기본 요청 주소이지만 formlogin을 disable로 설정하였기 때문에 동작 안함
// -> UsernamePasswordAuthenticationFilter 등록해줘야한다.
@Service
@RequiredArgsConstructor
public class PrincipalDetailsService implements UserDetailsService {
private final UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("시큐리티 로그인");
User userEntity = userRepository.findByUsername(username);
return new PrincipalDetails(userEntity);
}
}

View File

@@ -2,6 +2,7 @@ package com.security.jwt.config;
import com.security.jwt.filter.MyFilter1;
import com.security.jwt.filter.MyFilter2;
import com.security.jwt.filter.MyFilter3;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -13,7 +14,7 @@ public class FilterConfig {
public FilterRegistrationBean<MyFilter1> filter1() {
FilterRegistrationBean<MyFilter1> bean = new FilterRegistrationBean<>(new MyFilter1());
bean.addUrlPatterns("/*");
bean.setOrder(0); // 낮은 번호의 필터부터 실행 된다.
bean.setOrder(1); // 낮은 번호의 필터부터 실행 된다.
return bean;
}
@@ -21,7 +22,15 @@ public class FilterConfig {
public FilterRegistrationBean<MyFilter2> filter2() {
FilterRegistrationBean<MyFilter2> bean = new FilterRegistrationBean<>(new MyFilter2());
bean.addUrlPatterns("/*");
bean.setOrder(1); // 낮은 번호의 필터부터 실행 된다.
bean.setOrder(2); // 낮은 번호의 필터부터 실행 된다.
return bean;
}
@Bean
public FilterRegistrationBean<MyFilter3> filter3() {
FilterRegistrationBean<MyFilter3> bean = new FilterRegistrationBean<>(new MyFilter3());
bean.addUrlPatterns("/*");
bean.setOrder(0); // 낮은 번호의 필터부터 실행 된다.
return bean;
}

View File

@@ -1,13 +1,14 @@
package com.security.jwt.config;
import com.security.jwt.filter.MyFilter1;
import com.security.jwt.filter.MyFilter3;
import com.security.jwt.jwt.JwtAuthenticationFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import org.springframework.web.filter.CorsFilter;
@Configuration
@@ -19,12 +20,14 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// http.addFilterBefore(new MyFilter3(), SecurityContextPersistenceFilter.class);
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 세션 사용 X
.and()
.addFilter(corsFilter) // @CrossOrigin(인증X), 시큐리티 필터에 등록(인증O) 모든 요청이 corsFilter를 거친다.
.formLogin().disable()
.httpBasic().disable()
.addFilter(new JwtAuthenticationFilter(authenticationManager())) // AuthenticationManager
.authorizeRequests()
.antMatchers("/api/v1/user/**")
.access("hasRole('ROLE_USER') or hasRole('ROLE_MANAGER') or hasRole('ROLE_ADMIN')")

View File

@@ -12,23 +12,8 @@ public class MyFilter1 implements Filter {
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse res = (HttpServletResponse) servletResponse;
System.out.println("필터1");
// 토큰이 넘어오면
if(req.getMethod().equals("POST")) {
System.out.println("POST 요청됨");
String headerAuth = req.getHeader("Authorization");
System.out.println(headerAuth);
if (headerAuth != null && headerAuth.equals("cos")) {
filterChain.doFilter(req, res);
} else {
PrintWriter out = res.getWriter();
out.println("인증 안됨");
}
} else {
filterChain.doFilter(req, res);
}
filterChain.doFilter(servletRequest, servletResponse);
}
}

View File

@@ -0,0 +1,36 @@
package com.security.jwt.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class MyFilter3 implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse res = (HttpServletResponse) servletResponse;
// id, pw 정상적으로 들어와서 로그인이 완료 되면 토큰을 만들어주고 응답
// 요청할 때 마다 header에 Authorization에 value 값으로 토큰이 넘어온다.
// 넘어온 토큰이 내가 만든 토큰이 맞는지 검증만 하면 된다. ( RSA, HS256 )
if(req.getMethod().equals("POST")) {
System.out.println("POST 요청됨");
String headerAuth = req.getHeader("Authorization");
System.out.println(headerAuth);
if (headerAuth != null && headerAuth.equals("cos")) {
filterChain.doFilter(req, res);
} else {
PrintWriter out = res.getWriter();
out.println("인증 안됨");
}
} else {
filterChain.doFilter(req, res);
}
}
}

View File

@@ -0,0 +1,37 @@
package com.security.jwt.jwt;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// 스프링 시큐리티 에서 UsernamePasswordAuthenticationFilter는
// /login 요청해서 username, password를 전송하면 (post) 동작한다.
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final AuthenticationManager authenticationManager;
// /login 요청을 하면 로그인 시도를 위해서 실행되는 함수
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
System.out.println("JwtAuthenticationFilter : 로그인 시도중");
// 1. username, password 를 받는다.
// 2. 정상인지 로그인 시도를 한다.
// authenticationManager 로 로그인 시도를 하면
// -> PrincipalDetailsService가 호출
// -> loadUserByUsername() 메소드 실행
// 3. PrincipalDetials 를 세션에 담고 (권한 관리를 위해서)
// 4. JWT토큰을 만들어서 응답
return super.attemptAuthentication(request, response);
}
}

View File

@@ -0,0 +1,10 @@
package com.security.jwt.repository;
import com.security.jwt.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username);
}