1 minute read

Springboot 기준 Jwt api 인증

  1. 정상적인 로그인 절차를 거친 클라이언트에게 토큰을 지급한다
  2. 클라이언트는 인증 받은 토큰을 헤더에 Authorization 필드로 저장 후 통신을 진행한다.
  3. 모든 컨트롤러 요청은 Interceptor를 통해 토큰인증 절차를 진행한다.

maven dependency

<!-- jwt token authorization -->
<dependency>
	<groupId>io.jsonwebtoken</groupId>
	<artifactId>jjwt</artifactId>
	<version>0.7.0</version>
</dependency>

jwt 클래스

인증토큰을 발급하거나 검증하는데 사용한다.

import java.io.UnsupportedEncodingException;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.yourpakage.common.UnauthorizedException;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

@Component
public class JwtUtil {
	private static final String SALT = "yoursecretkey";

	public <T> String create(String key, T data, String subject) {
		String jwt = Jwts.builder().setHeaderParam("typ", "JWT").setHeaderParam("regDate", System.currentTimeMillis())
				.setSubject(subject).claim(key, data).signWith(SignatureAlgorithm.HS256, this.generateKey()).compact();
		return jwt;
	}

	private byte[] generateKey() {
		byte[] key = null;
		try {
			key = SALT.getBytes("UTF-8");
		} catch (UnsupportedEncodingException e) {

			e.printStackTrace();
		}

		return key;
	}
	
	public boolean isUsable(String jwt) {
		try{
			Jws<Claims> claims = Jwts.parser()
					  .setSigningKey(this.generateKey())
					  .parseClaimsJws(jwt);
			return true;
			
		}catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	
	
	
	
	public Map<String, Object> get(String key) {
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
		String jwt = request.getHeader("Authorization");
		Jws<Claims> claims = null;
		try {
			claims = Jwts.parser()
						 .setSigningKey(SALT.getBytes("UTF-8"))
						 .parseClaimsJws(jwt);
		} catch (Exception e) {
			throw new UnauthorizedException();
		}
		@SuppressWarnings("unchecked")
		Map<String, Object> value = (LinkedHashMap<String, Object>)claims.getBody().get(key);
		return value;
	}
}

사용자 지정 UnauthorizedException 클래스


public class UnauthorizedException extends RuntimeException{
	private static final long serialVersionUID = -2238030302650813813L;
	
	public UnauthorizedException() {
		super("계정 권한이 유효하지 않습니다.\n다시 로그인을 해주세요.");
	}
}

interceptor 추가

모든 컨트롤러 요청을 preHandle 매소드를 통해 거쳐가도록 설정
실질적인 토큰 인증을 진행한다.

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import com.yourpakage.common.util.JwtUtil;

@Component
public class AuthInterceptor implements HandlerInterceptor {
	private static final String HEADER_AUTH = "Authorization";

	@Autowired
	private JwtUtil jwtUtil;

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {

		final String token = request.getHeader(HEADER_AUTH);
    
		if (token != null && !token.equals("")) {
			if (jwtUtil.isUsable(token))
				return true;
		} else {
			response.setContentType("application/json");
			response.setCharacterEncoding("UTF-8");
			JSONObject resultJson = new JSONObject();

			resultJson.put("result_code", ResultStatus.UNAUTHORIZED.value());
			resultJson.put("err_msg", "Authentication has been expired");
			try {
				response.getWriter().write(resultJson.toString());
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return false;
	}
}

Webconfig 클래스 설정 추가
로그인이나 회원가입, 외부 도메인 callback(PG사 연동) 등의 인증 제외 URI를 설정한다.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import com.yourpakage.common.AuthInterceptor;

@Configuration
public class WebConfig implements WebMvcConfigurer{
	private static final String[] EXCLUDE_PATHS = {
        "your_exclude_path1","your_exclude_path2","your_exclude_path3"
            
    };
    @Autowired
    private AuthInterceptor authInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {    	
    	registry.addInterceptor(authInterceptor)
		.addPathPatterns("/**")
		.excludePathPatterns(EXCLUDE_PATHS);
    }
}

Categories:

Updated: