본문 바로가기
Spring|Spring-boot

JWT(2)

by oncerun 2020. 8. 18.
반응형

실제로 Json Web Token을 적용시키는 연습을 합니다.

 

Authorization은 인가입니다. 인증과 연결되어 사용됩니다.

인증은 사용자가 누구인지 증명하는 단계이고 여기서 발급이 된 JWT를 이용해서 사용자가 접근할 수 있는 권한을 확인하는 것이 인가 Authorization입니다.

 

Stateless 기존 웹개발에서는 상태를 유지하기 위해 session을 사용했지만 이번에는 모든 요청에 JWT을 확인해서 응답할 것입니다.

 

이러기 위해서 acessToken을 http Header를 통해서 전달할 것입니다.

 

모든 요청에대해서 토큰을 처리할 것이므로 Filter를 통해 토큰을 분석해서 사용자를 확인할 것입니다.

 

BasicAuthenticationFilter는 Spring에서 제공해주는 인증 필터입니다.

AuthenticationToken은 Spring내부에서만 사용되는 Token입니다.

가장 기본적인 UsernamePasswordAuthenticationToken을 활용할 생각입니다.

 

 

1. 필터를 추가하고 session정책을 정한다.

package kr.co.fastcampus.eatgo;


import kr.co.fastcampus.eatgo.filters.JwtAuthenticationFilter;
import kr.co.fastcampus.eatgo.utils.JwtUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import javax.servlet.Filter;

@Configuration
@EnableWebSecurity
public class SecurityJavaConfig extends WebSecurityConfigurerAdapter {

    @Value("${jwt.secret}")
    private String secret;

    @Override
    protected  void configure(HttpSecurity http) throws Exception {

        Filter filter = new JwtAuthenticationFilter(authenticationManager(),jwtUtil());

        http
                .cors().disable()
                .csrf().disable()
                .formLogin().disable()
                .headers().frameOptions().disable()
                .and()
                .addFilter(filter)
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public JwtUtil jwtUtil(){
        return new JwtUtil(secret);
    }
}

 

2.header에서 토큰을 얻어 SecurityContext에 설정

package kr.co.fastcampus.eatgo.filters;

import io.jsonwebtoken.Claims;
import kr.co.fastcampus.eatgo.utils.JwtUtil;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
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;

public class JwtAuthenticationFilter extends BasicAuthenticationFilter {

    private JwtUtil jwtUtil;

    public JwtAuthenticationFilter(AuthenticationManager authenticationManager, JwtUtil jwtUtil) {
        super(authenticationManager);
        this.jwtUtil = jwtUtil;
    }


    @Override
    protected void doFilterInternal(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain chain) throws IOException, ServletException {


        Authentication authentication = getAuthentication(request);

        if(authentication != null){

            SecurityContext context = SecurityContextHolder.getContext();
            context.setAuthentication(authentication);
        }

        chain.doFilter(request,response);

    }

    private Authentication getAuthentication(HttpServletRequest request){

        String token = request.getHeader("Authorization");

        if(token == null){
            return null;
        }

        Claims claims = jwtUtil.getClaims(token.substring("Bearer ".length()));

        Authentication authentication = new UsernamePasswordAuthenticationToken(claims,null);
        return authentication;
    }
}

 

3. JWT의 Claims를 얻는 클래스 구현

package kr.co.fastcampus.eatgo.utils;


import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;

import java.security.Key;

public class JwtUtil {


    private  Key key;

    public JwtUtil(String secret) {
        this.key = Keys.hmacShaKeyFor(secret.getBytes());

    }

    public String createToken(long userId, String name) {

        return Jwts.builder()
                .claim("userId",userId)
                .claim("name",name)
                .signWith(key, SignatureAlgorithm.HS256)
                .compact();
    }


    public Claims getClaims(String token) {

        return Jwts.parser()
                .setSigningKey(key)
                .parseClaimsJws(token)
                .getBody();
    }
}

 

테스트 

 

  JWT은 일부러 Test를 실패한 다음 실패 토큰 값을 얻어 붙여 넣었다.

 

반응형

댓글