안부 남기기

  • BlogIcon PCK 2018.03.08 19:54 신고

    메이킹러브님!!
    안녕하세요. spring security글 쓰신지 벌써 3-4년이 흘렀지만 참 유용하네요
    웹 개발 초보자인데 시큐리티 관련해서 이렇게 자세하고 친절한 글을 만나게 되니 너무 감사하네요
    다름이 아니라.. 질문이 있어 이렇게 연락드렸어요
    러브님의 글 대로 잘 구현하던 중.
    AuthenticationFailureHandler 부분에서 문제가 발생해서 이렇게 문의드려요
    CustomAuthenticationFailureHandler 클래스 구현 후
    로그인 시도를 하니, 올바른 아이디와 pw를 경우에는 다음 url로 잘 이동을 하는데
    없는 아이디인 경우나, pw가 틀린 경우에는 http 405 not allowed error(post method not allowed)가
    발생하네요 ㅜ
    request.getRequestDispatcher(defaultFailureUrl).forward(request, response);
    이부분이 문제를 일으키는거 같아요 포워드 부분을 빼고 response.sendRedirect로 하니 작동은 하는데 이경우에는 request에 setAttribute한 자원을 활용할 수 없어서 문제이구요 ㅜ
    러브님이 구현하신 그대로 CustomAuthenticationFailureHandler 클래스 구현했는데 무엇이 문제라 계속 405 not allowed error가 발생할까요 ㅜ
    제게 정답이나 길을 좀 알려주시면 너무 감사하겠습니다.
    (참고로 웹 개발한지 1년도 안된 초보라 리다이렉트랑 포워드에 대한 개념도 정확하게 모르고 있답니다 ㅜ)

    1. BlogIcon PCK 2018.03.09 03:01 신고

      이 부분은 Admincontroller에 requestmapping을 /login로 하여 get method도 인식하는 형태로 하니 풀렸는데.. 이렇게 구현하는게 맞는지 모르겠네요..
      또 다른 질문이 생겼는데 이 또한 AuthenticationFailureHandler 와 관련한 부분입니다.
      로그인 실패시, AuthenticationException에서 로그인 실패 이유를 알려주는데.. AuthenticationException.getMessage를 하면 항상 BadCredentialsException과 관련된 메시지만 출력됩니다.. 분명 없는 아이디로도 로그인으로 시도하는데 계속 배드크리덴셜만 뜨네요..
      로그를 따라가며 검증해보았는데 jdbcImpl 구현 클래스를 먼저 탄 후에 실패하면 authenticationFailureHandler 쪽으로 오는 것으로 확인했습니다. jdbcImpl 구현 클래스에서 userNamenotFound 후 throw를 하는데 이 throw가 authenticationFailureHandler로 오는건 아닌지요? 그럼 어디로 가는지...
      알려주시면 너무너무 감사할 것 같습니다.!!

    2. BlogIcon 메이킹러브 2018.03.09 15:20 신고

      안녕하세요..
      정말 몇년전에 써서 이제는 최신의 기술도 아닌 글에 칭찬을 해주시니 감사합니다..
      하지만 오늘 제가 답변 드리는것이 미진한 부분도 있어서 그 점에 있어서는 죄송합니다..
      제가 지금 이 소스를 github에서 다시 받아서 체크할 수 있는 여건이 아닌지라..디테일하게 봐드릴수가 없어서요..
      그래서 몇가지 부분은 제가 가이드만 잡아드릴수 밖에 없는 점을 말씀드려요..죄송합니다..

      여러가지 질문을 해주셨는데..먼저 이 부분에 대한 답을 해드려야 할 것 같네요..
      forward와 redirect와의 차이..
      예를 들어 A란 웹페이지에서 B란 웹페이지로 이동해야 하는 상황이 있다고 가정해보죠..
      이럴때 사용하는 방법으로 forward와 redirect가 있습니다..
      forward는 서버에서 직접 이동하는거에요..
      A페이지나 B페이지나 모두 동일한 WAS(이것도 예를 들어 Tomcat이라고 가정할께요)에서 제공하는 것이기 때문에..
      A페이지에서 B페이지로 서버 레벨에서의 이동이 가능합니다. 마치 자바에서 A 메소드 안에서 B 메소드 호출하는 그런 식으로 이해하시면 될듯 하네요..
      그러나 redirect는 서버에서 직접 이동하지 않습니다.
      redirect는 서버가 클라이언트(여기서는 웹브라우저겠죠)에게 B 페이지로 가라고 응답을 줍니다..
      그러면 브라우저는 그 응답을 받고 B 페이지로 가는거죠..
      즉 서버->웹브라우저->서버 이런 흐름으로 전개가 됩니다..
      이것은 우리가 웹브라우저 주소를 봐도 이해할 수 있습니다..
      A 페이지에서 B 페이지로 forward 방식으로 이동할땐..
      화면은 B 페이지를 보여주지만 웹브라우저의 URL은 A 페이지 것을 가르키고 있습니다.
      그것은 redirect 처럼 웹브라우저에게 B 페이지로 가라고 응답을 준게 아니라 서버 차원에서 바로 이동한것이기 때문에..
      웹브라우저는 A 페이지의 URL을 그대로 유지할 수가 있죠..
      그러나 redirect로 이동하게 되면 웹브라우저의 URL은 B 페이지의 것을 가르키게 됩니다.
      웹개발자로서 이 부분을 확실히 알아두어야 하는게..
      우리가 흔히 게시판을 만들때 글 등록하는 작업을 마치고 리스트 페이지를 보여쥬죠?
      그때 리스트 페이지를 보여주게끔 할때 redirect로 하게 됩니다..
      만약 이것을 forward로 하게 될 경우..
      브라우저 URL은 글 등록하는 URL로 남아 있는 상태에서 리스트 화면이 보여지기 때문에..
      F5 키를 눌러 새로고침을 할 경우 URL은 글 등록하는 URL로 존재하기 때문에 글을 다시 등록하는 상황이 벌어집니다..
      그래서 redirect로 하는 것이 일반적인거죠..redirect로 하게 되면 브라우저의 URL이 리스트 화면 URL이기 때문에
      F5 키를 눌러 새로고침을 해도 리스트 URL을 이용해서 새로고침을 하는 것이기 때문에 글을 다시 등록하는 상황이 없습니다..
      약간 설명이 곁가지로 빠졌네요..ㅎㅎ..
      이정도면 forward와 redirect 차이는 아시리라 생각되고..
      이제 405 에러에 대해 얘기해볼께요..

    3. BlogIcon 메이킹러브 2018.03.09 15:53 신고

      405 에러는 지원하지 않는 방법의 메소드로 접근할때 발생합니다..
      여기서 말하는 메소드는 HTTP 프로토콜의 메소드를 의미하는거에요..
      가장 많이 아는게 GET과 POST 이 2가지가 가장 잘 알려져 있죠..
      왜 알려져 있다..라고 말씀드리냐면 HTTP 프로토콜의 메소드는 이 2개만 있는게 아니기 때문입니다..
      GET, POST, PUT, DELETE, HEAD, OPTIONS, TRACE, CONNECT 이렇게 8가지가 있구요..
      앞의 4개는 웹개발할때 많이 쓰입니다..
      PUT과 DELETE는 Restful API 개발하실때 쓰일수도 있어요..
      암튼 이정도로 있다고만 알아두시고..
      이 메소드가 지원되지 않는 방법으로 접근할때 발생한다고 보시면 됩니다..
      그러면 왜 이런 상황이 발생하냐..
      login을 처리하는 URL을 접근하실땐 POST 방식을 쓰셨을거라고 추측하는데요..
      여기서 로그인 하는데 문제가 발생해서 CustomAuthenticationFailureHandler로 이동하셨을 겁니다..
      그리고 onAuthenticationFailure 메소드에서 forward로 특정 페이지로 이동하셨을꺼에요..
      이때 보셔야 할 것이 있습니다.
      forward로 이동한 페이지를 처리하는 Contrller 클래스의 메소드에 정의되어 있는 @RequestMapping에서
      method = RequestMethod.GET 으로 명시했다면 이 오류가 발생한 것은 맞는거에요..
      왜냐면 로그인을 처리하는 페이지로 이동했을때 POST 방식이었기 때문이죠..
      서버에서 페이지를 이동한 것이기 때문에 해당 페이지로 이동하는 것도 Request 방식에 있어서는 POST 방식 기존것을 그대로 유지하게 됩니다.
      근데 forward로 이동하는 URL에서 GET Method로 정의해버리면 이 부분이 맞지 않겠죠?
      이럴땐 @RequestMapping 부분의 method를 지워서 GET 방식과 POST 방식 모두 사용하게끔 하면 에러는 발생하지 않을겁니다..
      그러나 내부 코드를 모르기 때문에 일단 그 에러는 넘어갔더라도 다른 에러는 발생할 수 있을 가능성이 있구요..
      제가 spring-security.xml 에서 customAuthenticationFailureHandler를 설정할때 defaultFailureUrl로 /login.do?fail=true를 한게 있습니다..
      이 URL을 처리하게 되는 com.terry.springsecurity.controller.Login.java를 보시면 login.do를 처리하는 메소드인 login 메소드의 @RequestMapping 메소드에
      method 속성을 지정하지 않은걸 보실수 있습니다.
      이 method 속성을 지정하지 않으면 get, post 메소드를 모두 받아들일수 있기 때문에 forward 처리도 가능합니다..
      redirect를 했을때 정상적인 이유는 브라우저로 이동하게끔 명령을 내리면 그때는 GET 방식으로 이동하기 때문에 정상적으로 동작할 수 있었던거에요..
      지금 작성하신 소스를 볼 수가 없어서 이런 상황이지 않을까 해서 이렇게 답변 드리구요..

    4. BlogIcon 메이킹러브 2018.03.09 16:08 신고

      BadCredentialsException과 관련된 내용은 사실 소스를 좀 추적해봐야 알 수 있는 부분인데..
      일단 한가지 말씀드릴 것은 BadCredentialsException과 UsernameNotFoundException 모두..
      Spring Security가 제공하는 AuthenticationException 클래스의 subclass 입니다.
      바꿔말하면 BadCredentialsException과 UsernameNotFoundException 모두 AuthenticationException 클래스를 상속받은 클래스이죠..
      AuthenticationException 클래스 객체는 어디서 받느냐하면..
      CustomAuthenticationFailureHandler 클래스의 onAuthenticationFailure 메소드에서 파라미터로 받고 있습니다.
      이때 넘어오는게 BadCredentialsException 인지 UsernameNotFoundException 인지 체크해봐야 할 부분이 있습니다.
      만약 UsernameNotFoundException 클래스 객체를 받았다면 BadCredentialsException은 AuthenticationFailureHandler 핸들러를 거친 뒤에 어디선가 변환되어 넘어온거고..
      BadCredentialsException 클래스 객체를 받았다면 jdbcImpl 구현 클래스와 AuthenticationFailureHandler 핸들러 사이에서 변환되어서 넘어온거로 파악되겠죠..
      이걸 알 수 있는 방법은 instanceof 연산자를 사용하면 알 수 있습니다
      onAuthenticationFailure 메소드에서
      if(exception instanceof BadCredentialsException) 이게 true이면 BadCredentialsException 객체로 넘어온거고..
      마찬가지로 UsernameNotFoundException도 이 방법을 사용하면 알 수 있습니다..
      그러나 어느쪽이 됐든 이 부분은 디버그 모드로 돌리면서 소스 부분을 체크해봐야 알 수 있는 부분이라..
      이 부분은 답변을 드리기가 현재로썬 곤란합니다..이 점 죄송합니다..
      제가 지금은 소스를 받아서 확인을 해드릴수가 없는지라..이 부분은 제가 도와드리기가 어렵네요..ㅠㅠ..

  • 2017.11.23 16:16

    비밀댓글입니다

    1. BlogIcon 메이킹러브 2017.11.27 15:58 신고

      죄송합니다..글을 지금 봤네요..
      Spring Security 연재 글의 마지막 글에 이 소스가 있는 github 주소를 올려놨는데요..아직 거기까지는 보시지 않은듯 하네요..
      https://github.com/TerryChang/spring_security_blog_sample
      여기로 가시면 됩니다..

  • 2016.08.16 22:18

    비밀댓글입니다

  • BlogIcon 타우렌주술사 2016.02.09 23:39 신고

    늘 감사하게 생각합니다
    스프링 시큐리티를 항상 어렵다고 생각했는데 제타건담님 블로그를 보고 하나하나 이해하면서
    꼭 감사하다고 말씀드리고 싶었어요

    1. BlogIcon 메이킹러브 2016.02.17 14:22 신고

      오랜만에 관리차 들어왔는데..
      댓글 남겨주신거 보고 이렇게 남깁니다..
      퀄리티가 높은 글이 아닌데도..잘 봐주셔서 정말 고맙습니다..
      사실 오늘부터 전자정부 프레임워크를 Java Config 방식으로 설정하는 방법에 대한 내용으로 글을 쓸려고 하거든요..
      언제 완결되서 공개를 시킬지는 모르겠지만..
      그 글도 잘 봐주시면 고맙겠습니다..

  • BlogIcon 태준아빠 2015.04.03 08:44 신고

    안녕하세요.. 블로그 참고하여 spring security 를 적용 해보았습니다.

    권한관리, 그룹 관리 다 잘 됩니다..

    근데 중복로그인 체크 하기 위해

    <session-management invalid-session-url="/error3.do" >
    <concurrency-control max-sessions="1" session-registry-ref="sessionRegistry" error-if-maximum-exceeded="false" expired-url="/error3.do"/>
    </session-management>
    설정하였는데 중복 로그인 체크가 안되더군요..

    그래서

    <custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
    <custom-filter position="FORM_LOGIN_FILTER" ref="myAuthFilter" />

    <session-management session-authentication-strategy-ref="sas"/>

    로 바꿔 봤는데..


    Filter beans '<myAuthFilter>' and '<org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#com.withus.vodcaster_new#src/main/webapp/WEB-INF/spring/appServlet/security-
    context.xml#27>' have the same 'order' value. When using custom filters, please make sure the positions do not conflict with default filters. Alternatively you can disable the default filters by removing the
    corresponding child elements from <http> and avoiding the use of <http auto-config='true'>.

    에러가 발생합니다..

    조언좀 부탁 드립니다.


    감사합니다.

    1. BlogIcon 메이킹러브 2015.04.03 11:49 신고

      안녕하세요..
      댓글 써주신거에 대해 어제 확인을 해서..늦게나마 답변을 달아놨습니다..
      일단 답변은 거기에 조금 자세히 써놨구요..
      결론부터 말하자면 spring security 3.2.4 버그더라구요..
      spring securty 3.2.X 버전의 최신 버전인 3.2.7로 버전업을 해보시면 해결이 되실꺼에요..
      커스텀한 필터를 만들어서 필터순서를 인위적으로 조정하는 것에 대해서는 필터에 대한 이해가 높지 않으시면 오히려 오동작의 소지가 있어서 갠적으로 비추합니다..방법이 그것뿐이 없다면 어쩔수는 없겠지만서도..
      제가 예전에 쓰셨던 질문들에 답글을 달아놓았으니 한번 확인 부탁드립니다..
      늦게 글을 확인해서 죄송하고 고맙습니다..