coco3o 2021. 12. 13. 20:15 Show 예전에는 회원가입 및 로그인을 전통적인 방식으로 구현했지만 요즘은 사용하지 않는 추세이고, Spring Security와 OAuth 2.0을 사용한다. Spring Security ? 스프링 기반의 어플리케이션에서 보안을 위해 인증과 권한 부여를 사용해 접근을 제어하는 프레임워크이다. OAuth 2.0에 대해 궁금하다면 여기서 참고하면 될 것 같다. 이해하기 쉽게 설명을 잘해주셨다. 이제 Security를 이용해 회원가입 및 로그인을 구현해보자. 1. build.gradle
2. User , Role , UserRepository
User의 username은 id이기 때문에 unique 속성을 추가로 넣어줬다.
Username을 where 조건절에 넣어 데이터를 가져올 수 있도록 findByUsername 정의했다. 3. UserDto
4. SecurityConfig 생성Spring Security에서 WebSecurityConfigurerAdapter를 상속받은 클래스에서 메소드를 오버라이딩하여 조정할 수 있다.
5. 세션정보 저장 dto 클래스
인증된 사용자 정보를 세션에 저장하기 위한 클래스이다. User 엔티티 클래스에 직접 세션을 저장하려면 직렬화를 해야 하는데, 엔티티 클래스에 직렬화를 해준다면 추후에 다른 엔티티와 연관관계를 맺을 시 직렬화 대상에 다른 엔티티까지 포함될 수 있어 성능 이슈, 부수 효과 우려가 있다. -스프링 부트와 AWS로 혼자 구현하는 웹 서비스 中- 6. UserDetailsService와 UserDetails 구현 클래스
UserDetailsService의 loadUserByUsername 메소드 오버라이딩 후 구현
/* 주석 참고 */ 7. Service
사용자 비밀번호를 해쉬 암호화 후 레파지토리에 저장한다. 8. Controller
/auth/** 경로에 대해 권한 없이 접근 가능하도록 설정해뒀기에 각 url에 /auth/를 붙여주었다.
CustomUserDetailsService에서 세션정보를 저장하고 PostsIndexController 클래스에 가져와 각각 model에 담았다. 9. Mustacheheader.mustache
세션 유무에 따라 로그인 or 로그아웃을 할 수 있도록 했다. join.mustache
login.mustache
Spring Security에서 데이터 전달은 Form을 사용 (name 값으로 데이터 전달) JSON으로 데이터 전달 시 label for와 id를 사용 (헷갈리지 않기!) 10. 결과 확인10-1. 미 로그인 사용자 화면메인 검색 게시글 상세보기인증되지 않은 사용자는 메인화면, 검색, 상세보기만 가능하며, 글의 수정, 삭제 또한 불가능하다. 인증되지 않은 사용자가 글쓰기를 누르면 다음과 같이 로그인 화면으로 이동시킨다. 로그인 화면10-2. 회원가입 및 로그인 사용자 화면회원가입회원가입이 완료되면 로그인 화면으로 이동시키고 로그인이 완료되면 메인화면으로 이동한다. 인증된 사용자는 글쓰기가 가능하다. 글쓰기 후 메인화면 인증된 사용자 상세보기수정, 삭제 또한 가능하다. 마무리하며여기까지 일단 Spring Security로 회원가입과 로그인을 구현했다. 하지만 아직 보완해야 될 부분들이 몇 가지 있다. 1. csrf 문제- Spring Security에서 csrf 토큰 없이 요청하면 그 요청을 막아버린다. 임시로 csrf().disable()을 사용해 비활성화했지만, 이는 완전히 해결된 것은 아니다. 필자는 mustache를 템플릿 엔진으로 사용하고 있는데, mustache는 csrf 토큰을 기본적으로 제공해주지 않기 때문에 참 난감하다. >>해결 ( 포스트 보러 가기 ) 2. 세션 중복 코드 개선- 다음은 로그인 완료 시 세션정보를 가져와 보여주는 코드이다.
Controller의 각 메소드마다 위 코드가 반복되고 있다. 이는 추후에 수정이 필요할 경우 모든 부분을 하나씩 수정해야 할 것이다. 이렇게 될 경우 유지보수성이 떨어지고, 다른 문제가 생길 수도 있을 것이다. >>해결 ( 포스트 보러 가기 ) 3. 유효성 검사 및 중복 검사- 사용자가 회원가입 페이지에서 입력한 데이터 값이 서버로 전송되기 전에 특정 규칙에 맞게 입력되었는지, 가입하려는 아이디가 이미 존재하는지 등 확인하는 검증 단계가 반드시 필요할 것이다. >>해결 ( 유효성 검사 , 중복 검사 ) 4. 에러 메시지 출력- 만약 로그인 페이지 상태에서 잘못된 로그인 정보를 입력한다고 치면, 로그인에 실패했지만 아무런 에러 메시지를 보지 못하고 로그인 페이지만 보일 것이다. 로그인이 실패했으면 어떤 이유로 실패했는지 에러 메시지를 띄워주어야 한다고 생각한다. 그래서, AuthenticationFailureHandler를 구현했지만, SPRING_SECURITY_LAST_EXCEPTION의 키값을 머스테치에 어떻게 넘겨줘야 될지 모르겠다.. >>해결 ( 포스트 보러 가기 ) +++2022/05/21 추가+++4-1. UserDetailsService 세션 관련 문제- 한동안 바빠서 확인해보지 못했는데, 오늘 나에게도 위와 같은 문제가 있었다는 것을 알았다. 필자는 로그인 실패 처리를 담당하는 CustomAuthFailureHandler 클래스의 메소드에session.invalidate를 넣어주는 방법으로 우선 해결하였다. (이 방법은 절대 best practice가 아님) CustomAuthFailureHandler 관련 포스팅은 여기 에서 볼 수 있다. 좋은 해결 방법으로는 AuthenticationProvider를 커스터마이징하여 로그인 시 입력했던 id, pw와 UserDetails에서 가져온 User 객체의 id, pw를 비교 후 로그인에 성공했을 때 세션을 설정하는 방법인 것 같다. 생각지 못했던 문제를 짚어주신 user님 감사합니다. (__) |