관리 메뉴

개발하는 동그리

[Main Project] Spring Security + JWT 설정 본문

스테이츠 코드(백엔드)/Main Project

[Main Project] Spring Security + JWT 설정

개발하는 동그리 2022. 9. 29. 14:46
반응형

Dependencies

implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'com.auth0:java-jwt:4.0.0' 

 

Spring Security + JWT 설정에 필요한 클래스 

  • SecuritConfig
  • CorsConfig
  • PrincipalDetailsService
  • PrincipalDetails
  • JwtAuthenticationFilter
  • JwtAuthorizationFilter
  • JwtProperties

 

SecurityConfig Class

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {

    private final CorsFilter corsFilter;
    private final UsersRepository usersRepository;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.headers().frameOptions().disable();
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .httpBasic()
                .disable()
                .apply(new CustomDsl())
                .and()
                .authorizeRequests()
                .antMatchers("/v1/company/**")
                .access("hasRole('ROLE_COMPANY') or hasRole('ROLE_ADMIN')")
                .antMatchers("/v1/customer/**")
                .access("hasRole('ROLE_CUSTOMER') or hasRole('ROLE_ADMIN')")
                .anyRequest().permitAll();


        return http.build();
    }


    public class CustomDsl extends AbstractHttpConfigurer<CustomDsl, HttpSecurity> {

        @Override
        public void configure(HttpSecurity builder) {
            AuthenticationManager authenticationManager = builder
						.getSharedObject(AuthenticationManager.class);
            builder
                    .addFilter(corsFilter)
                    .addFilter(new JwtAuthenticationFilter(authenticationManager))
                    .addFilter(new JwtAuthorizationFilter(authenticationManager
						,usersRepository));
        }
    }
}

 

CorsConfig Class

@Configuration
public class CorsConfig {

    @Bean
    public CorsFilter corsFilter() {

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("http://localhost:3000");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        config.addExposedHeader("Authorization");

        source.registerCorsConfiguration("/**", config);

        return new CorsFilter(source);
    }
}

 

PrincipalDetails Class

@Getter
@Setter
public class PrincipalDetails implements UserDetails {

    private Users users;

    public PrincipalDetails(Users users) {
        this.users = users;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        users.getRoleList().forEach(n -> {
            authorities.add(() -> n);
        });
        return authorities;
    }

    @Override
    public String getUsername() {
        return users.getEmail();
    }

    @Override
    public String getPassword() {
        return users.getPassword();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

 

PrincipalDetailsService Class

@Service
@RequiredArgsConstructor
public class PrincipalDetailsService implements UserDetailsService {

    private final UsersRepository usersRepository;

    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        Users usersEntity = usersRepository.findByEmail(email);

        return new PrincipalDetails(usersEntity);
    }
}

 

JwtAuthenticationFilter Class

@Slf4j
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private final AuthenticationManager authenticationManager;

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request
    , HttpServletResponse response) throws AuthenticationException {

        

        try {
            ObjectMapper om = new ObjectMapper();
            Users users = om.readValue(request.getInputStream(), Users.class);

            UsernamePasswordAuthenticationToken authenticationToken =
            new UsernamePasswordAuthenticationToken(users.getEmail(), users.getPassword());

            Authentication authentication =
            authenticationManager.authenticate(authenticationToken);

            return authentication;
        } catch (IOException e) {
            log.error("Error : ", e);
        }
        return null;
    }


    @Override
    protected void successfulAuthentication(HttpServletRequest request,
    HttpServletResponse response, FilterChain chain, Authentication authResult) {

        System.out.println("successfulAuthentication");
        PrincipalDetails principalDetails = (PrincipalDetails) authResult.getPrincipal();

        String jwtToken = JWT.create()
                .withSubject(principalDetails.getUsername())
                .withExpiresAt(new Date(System.currentTimeMillis() +
				 (JwtProperties.EXPIRATION_TIME)))
                .withClaim("id", principalDetails.getUsers().getId())
                .withClaim("email", principalDetails.getUsers().getEmail())
                .withClaim("username", principalDetails.getUsers().getUsername())
                .sign(Algorithm.HMAC512(JwtProperties.SECRET));
        response.addHeader(JwtProperties.HEADER_STRING,JwtProperties.TOKEN_PREFIX + jwtToken);
    }
}

 

JwtAuthorizationFilter Class

public class JwtAuthorizationFilter extends BasicAuthenticationFilter {

    private final UsersRepository usersRepository;

    public JwtAuthorizationFilter(AuthenticationManager authenticationManager,
 UsersRepository usersRepository) {
        super(authenticationManager);
        this.usersRepository = usersRepository;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
    		FilterChain chain) throws IOException, ServletException {
        String jwtHeader = request.getHeader(JwtProperties.HEADER_STRING);

        if (jwtHeader == null || !jwtHeader.startsWith(JwtProperties.TOKEN_PREFIX)) {
            chain.doFilter(request, response);
            return;
        }
        String jwtToken = jwtHeader.replace(JwtProperties.TOKEN_PREFIX, "");

        String email = JWT.require(Algorithm.HMAC512(JwtProperties.SECRET)).build().
        	verify(jwtToken).getClaim("email").asString();

        if (email != null) {
            Users usersEntity = usersRepository.findByEmail(email);
            PrincipalDetails principalDetails = new PrincipalDetails(usersEntity);
            Authentication authentication = 
            	new UsernamePasswordAuthenticationToken(principalDetails, null, 
                 	principalDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
            chain.doFilter(request, response);
        } else {
            super.doFilterInternal(request, response, chain);
        }
    }
}

 

JwtProperties

public interface JwtProperties {

   String SECRET = {secret_key}
   int EXPIRATION_TIME = {token_expiration_time} 
   String TOKEN_PREFIX = "Bearer ";
   String HEADER_STRING = "Authorization";
}

 

반응형