package kr.wisestone.owl.service.impl; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jws; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import kr.wisestone.owl.constant.MsgConstants; import kr.wisestone.owl.domain.ApiToken; import kr.wisestone.owl.domain.User; import kr.wisestone.owl.exception.ApiAuthException; import kr.wisestone.owl.exception.OwlRuntimeException; import kr.wisestone.owl.repository.ApiTokenRepository; import kr.wisestone.owl.service.ApiTokenService; import kr.wisestone.owl.service.UserService; import kr.wisestone.owl.util.ConvertUtil; import kr.wisestone.owl.util.DateUtil; import kr.wisestone.owl.util.WebAppUtil; import kr.wisestone.owl.vo.ApiTokenVo; import kr.wisestone.owl.vo.UserVo; import kr.wisestone.owl.web.form.ApiTokenForm; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Service; import java.io.UnsupportedEncodingException; import java.util.Date; import java.util.List; import java.lang.Long; import com.fasterxml.jackson.databind.ObjectMapper; @Service public class ApiTokenServiceImpl extends AbstractServiceImpl> implements ApiTokenService { private static final String ENCRYPT_STRING = "mpxowl"; private static final String DATA_KEY = "user"; static final Logger log = LoggerFactory.getLogger(ApiTokenServiceImpl.class); @Autowired private ApiTokenRepository apiTokenRepository; @Autowired protected WebAppUtil webAppUtil; // 토큰 생성 @Override public ApiToken add(ApiTokenForm apiTokenForm) { ApiToken apiToken = ConvertUtil.copyProperties(apiTokenForm, ApiToken.class); String appName = apiToken.getAppName(); apiToken.setUser(this.webAppUtil.getLoginUserObject()); // 기존 토큰 삭제 this.remove(null); UserVo user = this.webAppUtil.getLoginUser(); if (appName != null && !appName.isEmpty()) { Long currentTime = System.currentTimeMillis(); Date now = new Date(currentTime); String token = Jwts.builder() .setSubject(appName) .setHeaderParam("typ", "JWT") .setExpiration(DateUtil.addDays(now, 36500)) .setIssuedAt(now) .claim(DATA_KEY, user) .signWith(SignatureAlgorithm.HS256, this.generateKey()) .compact(); apiToken.setToken(token); } return this.apiTokenRepository.save(apiToken); } // 키 생성 private byte[] generateKey(){ byte[] key = null; try { key = ENCRYPT_STRING.getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { log.error("Making secret Key Error :: ", e); } System.out.println("비밀 key : " + key); return key; } //JWT 복호화 private UserVo getUserVo(String jwt) { //결과값 = Claims Jws claims = decryption(jwt); if (claims == null) return null; ObjectMapper objectMapper = new ObjectMapper(); //반환 타입은 LinkedHashMap 이다. 이를 User 타입으로 변환하기 위해 ObjectMapper 사용 try { return objectMapper.convertValue(claims.getBody().get(DATA_KEY), UserVo.class); } catch (Exception ex) { log.debug(ex.getMessage()); } return null; } private Jws decryption(String jwt) { //결과값 = Claims Jws claims = null; try { //비밀키를 이용해서 복호화 하는 작업 claims = Jwts.parser() .setSigningKey(this.generateKey()) .parseClaimsJws(jwt); } catch (Exception e) { log.debug(e.getMessage(), e); } return claims; } // 토큰 조회 @Override public ApiTokenVo find() { User user = this.webAppUtil.getLoginUserObject(); return this.find(user.getId()); } private ApiTokenVo find(Long userId) { if (userId != null) { List apiTokens = this.apiTokenRepository.findByUserId(userId); if (apiTokens != null && apiTokens.size() > 0) { return ConvertUtil.copyProperties(apiTokens.get(0), ApiTokenVo.class); } } return null; } // 토큰 사용자 인증, 인증후 사용자 가져오기 @Override public UserVo certification(String token) { UserVo userVo = this.getUserVo(token); if (userVo != null && containsToken(userVo, token)) { return userVo; } else { throw new ApiAuthException( this.messageAccessor.getMessage(MsgConstants.ERROR_TOKEN)); } } // 토큰으로 찾기 private ApiToken find(String token) { List apiTokens = this.apiTokenRepository.findByToken(token); if (apiTokens != null && apiTokens.size() > 0) { return apiTokens.get(0); } return null; } // 토큰 값이 db에 존재하는지 확인 private boolean containsToken(UserVo userVo, String token) { List apiTokens = this.apiTokenRepository.findByUserId(userVo.getId()); if (apiTokens != null && apiTokens.size() > 0) { return apiTokens.get(0).getToken().equals(token); } return false; } // 토큰 삭제 @Override public void remove(ApiTokenForm apiTokenForm) { ApiTokenVo apiTokenVo = this.find(); if (apiTokenVo != null) { this.apiTokenRepository.deleteById(apiTokenVo.getId()); } } @Override protected JpaRepository getRepository() { return this.apiTokenRepository; } }