티스토리 뷰

반응형
package com.inspection.oauth2.interceptor; import java.io.IOException; import java.security.Principal; import java.util.Collection; import javax.servlet.RequestDispatcher; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.sql.DataSource; import org.apache.commons.lang3.builder.ToStringBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.InsufficientAuthenticationException; import org.springframework.security.core.Authentication; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.crypto.codec.Base64; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import com.inspection.core.security.service.InspectionUserDetails; @EnableAutoConfiguration public class RefreshTokenIssueBeforeAccessTokenCheckIntercpetor extends HandlerInterceptorAdapter { private static Logger LOG = LoggerFactory.getLogger(RefreshTokenIssueBeforeAccessTokenCheckIntercpetor.class); private DataSource dataSource; public RefreshTokenIssueBeforeAccessTokenCheckIntercpetor(DataSource dataSource) { this.dataSource = dataSource; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String url = request.getRequestURI(); if (url.equals("/v1/oauth/token")) { String grantType = request.getParameter("grant_type"); if (grantType.equals("refresh_token")) { // refresh token 일때 재발급 하기전에 우선 검색해본다. // client 부분 먼저 인증해본다. Authentication authentication = (Authentication) request.getUserPrincipal(); if (!authentication.isAuthenticated()) { throw new InsufficientAuthenticationException("The client is not authenticated."); } String clientId = getClientId(request.getHeader("Authorization")); if(!"key".equals(clientId)) { return true; } String refreshToken = request.getParameter("refresh_token"); // refreshToken으로 사용자 인증 정보를 가져온다. OAuth2Authentication oauth2Authentication = tokenStore().readAuthenticationForRefreshToken(refreshToken); UserDetails userDetails = (InspectionUserDetails) oauth2Authentication.getUserAuthentication() .getPrincipal(); LOG.info(ToStringBuilder.reflectionToString(userDetails)); // 발급된 사용자 refreshToken 정보로 accessToken을 가져온다. Collection<OAuth2AccessToken> accessTokens = tokenStore() .findTokensByUserName(userDetails.getUsername()); if (accessTokens == null) { // 기존 발급된 accessToken이 없을 때 refreshToken 새로 발급 return true; } // 아니면 인증 정보를 가져와서 reponse로 뿌려준다. OAuth2AccessToken oauth2AccessToken = accessTokens.iterator().next(); LOG.info(oauth2AccessToken.getValue()); request.setAttribute("oauth2", oauth2AccessToken); RequestDispatcher rd = request.getRequestDispatcher("/v1/test/oauth2"); rd.forward(request, response); return false; } } return true; } /** * This implementation is empty. */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } protected String getClientId(Principal principal) { Authentication client = (Authentication) principal; if (!client.isAuthenticated()) { throw new InsufficientAuthenticationException("The client is not authenticated."); } String clientId = client.getName(); if (client instanceof OAuth2Authentication) { // Might be a client and user combined authentication clientId = ((OAuth2Authentication) client).getOAuth2Request().getClientId(); } return clientId; } @Bean public JdbcTokenStore tokenStore() { return new JdbcTokenStore(dataSource); } /** * client 가져오기 * @author 정명성 * @create date : 2016. 8. 3. * @param header * @param request * @return * @throws IOException */ private String getClientId(String header) throws IOException { byte[] base64Token = header.substring(6).getBytes("UTF-8"); byte[] decoded; try { decoded = Base64.decode(base64Token); } catch (IllegalArgumentException e) { throw new BadCredentialsException("Failed to decode basic authentication token"); } String token = new String(decoded, "UTF-8"); int delim = token.indexOf(":"); if (delim == -1) { throw new BadCredentialsException("Invalid basic authentication token"); } return token.substring(0, delim); } }

@RequestMapping(value = "/test/oauth2") public ResponseEntity RefreshTokenExistAccessToken(HttpServletRequest request) { OAuth2AccessToken oauth2AccessToken = (OAuth2AccessToken) request.getAttribute("oauth2"); HttpHeaders headers = new HttpHeaders(); headers.set("Cache-Control", "no-store"); headers.set("Pragma", "no-cache"); return new ResponseEntity<OAuth2AccessToken>(oauth2AccessToken, headers, HttpStatus.OK); }

용도는 refresh_token을 발급했을때 access_token이 만료가 안된 상태면 access_token을 그대로 내보낼려고 했다.

이걸 한 이유는 안드로이드 앱에서 뻗는 경우가 있다고해서 그 액션이 안뻗게 만들려고 했었는데,
원인을 확인한 바. 안드로이드 앱에서 메모리 릭이 발생되서 문제가 생겼던 것이였다.

위 코드는 spring oauth2 내부적으로 돌아가는 부분 코드를 발쵀해서 적용한 것이기 때문에 
뭐 좀더 경험할 수 있었다.


반응형