session을 사용 하지 않는 웹애플리케이션 개발

2,401 views
Skip to first unread message

코바

unread,
Feb 9, 2012, 2:37:53 AM2/9/12
to Korea Spring User Group
안녕하십니까

유령 회원 코바입니다.

다른 아니라 모바일 웹을 개발 하고 있는데, 이번에 고객으로 부터 저런 요청을 받았습니다

oauth를 사용 하여 시스템을 개발 하는데, access토큰만 이용 해서 세션을 사용 하지 않고 개발 해달라고 하는군요

사실 스프링 시큐리티 사용 해서 oauth 프로바인더와 연동해서 로그인하여 사용 하고 있었는데

많이 개발된 시점에서 바꿔 달라고 해서 당황 스럽네요

여러곳을 찾아보니

spring security에서

SecurityContextPersistenceFilter
SecurityContextHolder
HttpSessionSecurityContextRepository
이 클래스를 참조하여
구현 하면된다고 하더군요

그런데 막상 해볼라고 하니 감이 안잡히네요

혹시 이런부분을 구현 해보신분이 계신지 아님 좋은 방법인 존재 하는지

가르쳐 주시면 감사하겠습니다.

고종봉

unread,
Feb 9, 2012, 8:46:01 AM2/9/12
to ks...@googlegroups.com
image.png

그림을 보시면...

왼쪽에 Security Filter Chain 중 SecurityContextPersistenceFilter에서 요청 시 인증정보를 복구하는 역할을 하는데요.


를 보시면,, SecurityContextRepository로부터 SecurityContextHolder를 얻는데요.

이 때 SecurityContextRepository는 구현체가 아니라 자바 인터페이스에요.

기본 구현체로 HttpSessionSecurityContextRepository를 사용하고 있는데,


얘 대신 CookieBasedSecurityContextRepository implements SecurityContextRepository 클래스를 만드시면 되요.


SecurityContextRepository 인터페이스에 정의된 메서드들 다 구현해주시면 되구요.

메서드 구현은 HttpSessionSecurityContextRepository 소스를 보고 수정해서 사용하심 되요.

자세한 내용은 저도 소스를 안봐서. ^^;

소스와 API 문서, 레퍼런스만 잘 활용해도 왠만큼은 해결하실 수 있으실 거에요. (영어에 거부감만 없으시다면..ㅎ)



2012년 2월 9일 오후 4:37, 코바 <sbc...@gmail.com>님의 말:

--
Google 그룹스 'Korea Spring User Group' 그룹에 가입했으므로 본 메일이 전송되었습니다.
이 그룹에 게시하려면 ks...@googlegroups.com(으)로 이메일을 보내세요.
그룹에서 탈퇴하려면 ksug+uns...@googlegroups.com로 이메일을 보내주세요.
더 많은 옵션을 보려면 http://groups.google.com/group/ksug?hl=ko에서 그룹을 방문하세요.


image.png

선영욱

unread,
Feb 9, 2012, 6:05:45 PM2/9/12
to ks...@googlegroups.com
와~맵이 정말 도움이 많이 되는 정보인거 같습니다.
 
감사합니다.

이상용

unread,
Feb 9, 2012, 7:30:08 PM2/9/12
to ks...@googlegroups.com
멋진 정보 감사합니다^^
 
오늘도 즐거운 하루 되시기를..^^

2012년 2월 10일 오전 8:05, 선영욱 <twinmo...@gmail.com>님의 말:
와~맵이 정말 도움이 많이 되는 정보인거 같습니다.
 
감사합니다.

--

박용권

unread,
Feb 9, 2012, 7:52:15 PM2/9/12
to ks...@googlegroups.com
스프링 시큐리티는 필터 구조에 대해서 이해하고 사용하면 훨씬 유용하게 사용할 수 있는 녀석이죠 ^^;

좋은 그림입니다! +_+)b

2012년 2월 9일 오후 10:46, 고종봉 <mercu...@gmail.com>님의 말:
image.png

황용대

unread,
Feb 9, 2012, 8:53:51 PM2/9/12
to ks...@googlegroups.com
���� ����� �ξ�� ��Ű ���ؽ�Ʈ �������丮 �ҽ��� �����ص帳�ϴ�.

���� ��� ��ť��Ƽ���ؽ�Ʈ�������丮�� ������ ���ε���
http�������ؽ�Ʈ�������丮 �ҽ��� �����ٰ� ��Ű�� �°� ��������������

public class CookieSecurityContextRepository implements
SecurityContextRepository, InitializingBean {
public static final String SPRING_SECURITY_CONTEXT_KEY =
"SPRING_SECURITY_CONTEXT";

protected final Log logger = LogFactory.getLog(this.getClass());

private Class<? extends SecurityContext> securityContextClass = null;

private boolean disableUrlRewriting = false;
private String cookieName;
private String cookieKey;

private AuthenticationTrustResolver authenticationTrustResolver = new
AuthenticationTrustResolverImpl();

public SecurityContext loadContext(HttpRequestResponseHolder
requestResponseHolder) {
HttpServletRequest request = requestResponseHolder.getRequest();
HttpServletResponse response = requestResponseHolder.getResponse();

Authentication cookie = null;
try {
cookie = getAuthenticationFromCookie(request);
} catch (JsonParseException e) {
logger.error(e);
} catch (JsonMappingException e) {
logger.error(e);
} catch (IOException e) {
logger.error(e);
}

if (cookie == null) {
if (logger.isDebugEnabled()) {
logger.debug("No SecurityContext was available A new one will be created.");
}
return generateNewContext();
}

SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(cookie);

requestResponseHolder.setResponse(new
SaveToCookieResponseWrapper(response, context.hashCode()));

return context;
}

private Authentication getAuthenticationFromCookie(HttpServletRequest
request) throws JsonParseException, JsonMappingException, IOException {
logger.debug("getAuthenticationFromCookie");
if (request == null) {
if (logger.isDebugEnabled()) {
logger.debug("No cookie currently exists");
}
return null;
}

Cookie cookie = CookieUtils.getCookieByName(request, cookieName);
if(cookie == null) {
if (logger.isDebugEnabled()) {
logger.debug("No token cookie currently exists");
}
return null;
}
String tokens = CookieUtils.decodeCookie(cookie.getValue(), cookieKey);

logger.debug("CookieName = "+ tokens);
ObjectMapper mapper = new ObjectMapper();
ActionUserDetails user = mapper.readValue(tokens, ActionUserDetails.class);

cookie = CookieUtils.getCookieByName(request, "sign");
if(cookie == null) {
if (logger.isDebugEnabled()) {
logger.debug("No signature cookie currently exists");
}
return null;
}
String credentials = CookieUtils.decodeCookie(cookie.getValue(), cookieKey);

if(credentials == null)
return null;

CookieAuthenticationToken newAuthentication = new
CookieAuthenticationToken(user, credentials, user.getAuthorities());
newAuthentication.setAuthenticated(true);
return newAuthentication;
}

public void saveContext(SecurityContext context, HttpServletRequest
request, HttpServletResponse response) {

}

public boolean containsContext(HttpServletRequest request) {
Cookie cookie = CookieUtils.getCookieByName(request, cookieName);

if (cookie == null) {
return false;
}

if (cookie.getValue().length() == 0) {
return false;
}

return true;
}

/**
* By default, calls {@link SecurityContextHolder#createEmptyContext()} to
* obtain a new context (there should be no context present in the holder
* when this method is called). Using this approach the context creation
* strategy is decided by the {@link SecurityContextHolderStrategy} in use.
* The default implementations will return a new
* <tt>SecurityContextImpl</tt>.
* <p>
* An alternative way of customizing the <tt>SecurityContext</tt>
* implementation is by setting the <tt>securityContextClass</tt> property.
* In this case, the method will attempt to invoke the no-args constructor
* on the supplied class instead and return the created instance.
*
* @return a new SecurityContext instance. Never null.
*/
SecurityContext generateNewContext() {
SecurityContext context = null;

if (securityContextClass == null) {
context = SecurityContextHolder.createEmptyContext();
return context;
}

try {
context = securityContextClass.newInstance();
} catch (Exception e) {
ReflectionUtils.handleReflectionException(e);
}
return context;
}

/**
* Allows the use of session identifiers in URLs to be disabled. Off by
* default.
*
* @param disableUrlRewriting
* set to <tt>true</tt> to disable URL encoding methods in the
* response wrapper and prevent the use of <tt>jsessionid</tt>
* parameters.
*/
public void setDisableUrlRewriting(boolean disableUrlRewriting) {
this.disableUrlRewriting = disableUrlRewriting;
}

public String getCookieName() {
return cookieName;
}

public void setCookieName(String cookieName) {
this.cookieName = cookieName;
}

public String getCookieKey() {
return cookieKey;
}

public void setCookieKey(String cookieKey) {
this.cookieKey = cookieKey;
}

// ~ Inner Classes
//
==================================================================================================

final class SaveToCookieResponseWrapper extends
SaveContextOnUpdateOrErrorResponseWrapper {
private int contextHashBeforeChainExecution;

public SaveToCookieResponseWrapper(HttpServletResponse response, int
contextHashBeforeChainExecution) {
super(response, disableUrlRewriting);
this.contextHashBeforeChainExecution = contextHashBeforeChainExecution;
}

@Override
protected void saveContext(SecurityContext context) {
final Authentication authentication = context.getAuthentication();

// See SEC-776
if (authentication == null ||
authenticationTrustResolver.isAnonymous(authentication)) {
if (logger.isDebugEnabled()) {
logger.debug("SecurityContext is empty or anonymous - context will not
be stored.");
}
return;
}

// If HttpSession exists, store current SecurityContextHolder
// contents but only if the SecurityContext has actually changed
// (see JIRA SEC-37)
// We also check that the session contains the context, in case a
// new session has been created (SEC-1561)
if (context.hashCode() != contextHashBeforeChainExecution) {
}
}
}

@Override
public void afterPropertiesSet() throws Exception {
Assert.hasLength(cookieName, "Cookie name cannot be empty or null");
Assert.hasLength(cookieKey, "Cookie key cannot be empty or null");
}
}
2012�� 02�� 09�� 16:37, �ڹ� �� ��:
> �ȳ��Ͻʴϱ�
>
> ���� ȸ�� �ڹ��Դϴ�.
>
> �ٸ� �ƴ϶� ����� ���� ���� �ϰ� �ִµ�, �̹� �?���� ���� �� ��û�� �޾ҽ��ϴ�
>
> oauth�� ��� �Ͽ� �ý����� ���� �ϴµ�, access��ū�� �̿� �ؼ� ������ ��� ���� �ʰ� ���� �ش޶�� �ϴ±���
>
> ��� ������ ��ť��Ƽ ��� �ؼ� oauth ���ι��δ��� �����ؼ� �α����Ͽ� ��� �ϰ� �־�µ�
>
> ���� ���ߵ� �������� �ٲ� �޶�� �ؼ� ��Ȳ �����׿�
>
> �������� ã�ƺ���
>
> spring security����
>
> SecurityContextPersistenceFilter
> SecurityContextHolder
> HttpSessionSecurityContextRepository
> �� Ŭ������ �����Ͽ�
> ���� �ϸ�ȴٰ� �ϴ�����
>
> �׷��� ���� �غ���� �ϴ� ���� �������׿�
>
> Ȥ�� �̷��κ��� ���� �غ��ź��� ����� �ƴ� ���� ����� ���� �ϴ���
>
> ������ �ֽø� �����ϰڽ��ϴ�.
>

코바

unread,
Feb 11, 2012, 10:33:56 AM2/11/12
to ks...@googlegroups.com
와 늦었지만 좋은 자료 감사합니다 !!! 역시 공부는 더 해야 할듯합니다 !

코바

unread,
Feb 11, 2012, 10:34:34 AM2/11/12
to ks...@googlegroups.com
헉 글자가 깨지긴 하지만 소스는 엄청나게 큰 도움이 될 것 같습니다 !!! 정말 감사합니다

역시 좋으신분 많으시네요 

머큐짱(고종봉)

unread,
Jun 29, 2012, 7:36:30 PM6/29/12
to ks...@googlegroups.com
(황용대 님의 글 : 인코딩 복원)

예전에 만들어 두었던 쿠키 컨텍스트 리파지토리 소스를 공유해드립니다.

별건 없고 시큐리티컨텍스트리파지토리를 구현한 것인데요
http세션컨텍스트리파지토리 소스를 가져다가 쿠키에 맞게 수정한정도예요
2012년 2월 10일 금요일 오전 10시 53분 51초 UTC+9, 백일몽 님의 말:
占쏙옙占쏙옙 占쏙옙占쏙옙占�占싸억옙占�占쏙옙키 占쏙옙占쌔쏙옙트 占쏙옙占쏙옙占쏙옙占썰리 占쌀쏙옙占쏙옙 占쏙옙占쏙옙占쌔드립占싹댐옙.

占쏙옙占쏙옙 占쏙옙占�占쏙옙큐占쏙옙티占쏙옙占쌔쏙옙트占쏙옙占쏙옙占쏙옙占썰리占쏙옙 占쏙옙占쏙옙占쏙옙 占쏙옙占싸듸옙占쏙옙
http占쏙옙占쏙옙占쏙옙占쌔쏙옙트占쏙옙占쏙옙占쏙옙占썰리 占쌀쏙옙占쏙옙 占쏙옙占쏙옙占쌕곤옙 占쏙옙키占쏙옙 占승곤옙 占쏙옙占쏙옙占쏙옙占쏙옙占쏙옙占쏙옙占쏙옙

2012占쏙옙 02占쏙옙 09占쏙옙 16:37, 占쌘뱄옙 占쏙옙 占쏙옙:
> 占싫놂옙占싹십니깍옙
>
> 占쏙옙占쏙옙 회占쏙옙 占쌘뱄옙占쌉니댐옙.
>
> 占쌕몌옙 占싣니띰옙 占쏙옙占쏙옙占�占쏙옙占쏙옙 占쏙옙占쏙옙 占싹곤옙 占쌍는듸옙, 占싱뱄옙 占�占쏙옙占쏙옙 占쏙옙占쏙옙 占쏙옙 占쏙옙청占쏙옙 占쌨았쏙옙占싹댐옙
>
> oauth占쏙옙 占쏙옙占�占싹울옙 占시쏙옙占쏙옙占쏙옙 占쏙옙占쏙옙 占싹는듸옙, access占쏙옙큰占쏙옙 占싱울옙 占쌔쇽옙 占쏙옙占쏙옙占쏙옙 占쏙옙占�占쏙옙占쏙옙 占십곤옙 占쏙옙占쏙옙 占쌔달띰옙占�占싹는깍옙占쏙옙
>
> 占쏙옙占�占쏙옙占쏙옙占쏙옙 占쏙옙큐占쏙옙티 占쏙옙占�占쌔쇽옙 oauth 占쏙옙占싸뱄옙占싸댐옙占쏙옙 占쏙옙占쏙옙占쌔쇽옙 占싸깍옙占쏙옙占싹울옙 占쏙옙占�占싹곤옙 占쌍억옙쨉占�>
> 占쏙옙占쏙옙 占쏙옙占쌩듸옙 占쏙옙占쏙옙占쏙옙占쏙옙 占쌕뀐옙 占쌨띰옙占�占쌔쇽옙 占쏙옙황 占쏙옙占쏙옙占쌓울옙
>
> 占쏙옙占쏙옙占쏙옙占쏙옙 찾占싣븝옙占쏙옙
>
> spring security占쏙옙占쏙옙
>
> SecurityContextPersistenceFilter
> SecurityContextHolder
> HttpSessionSecurityContextRepository
> 占쏙옙 클占쏙옙占쏙옙占쏙옙 占쏙옙占쏙옙占싹울옙
> 占쏙옙占쏙옙 占싹몌옙홱鳴占�占싹댐옙占쏙옙占쏙옙
>
> 占쌓뤄옙占쏙옙 占쏙옙占쏙옙 占쌔븝옙占쏙옙占�占싹댐옙 占쏙옙占쏙옙 占쏙옙占쏙옙占쏙옙占쌓울옙
>
> 혹占쏙옙 占싱뤄옙占싸븝옙占쏙옙 占쏙옙占쏙옙 占쌔븝옙占신븝옙占쏙옙 占쏙옙占쏙옙占�占싣댐옙 占쏙옙占쏙옙 占쏙옙占쏙옙占�占쏙옙占쏙옙 占싹댐옙占쏙옙
>
> 占쏙옙占쏙옙占쏙옙 占쌍시몌옙 占쏙옙占쏙옙占싹겠쏙옙占싹댐옙.
>

Reply all
Reply to author
Forward
0 new messages