로그인과 로그아웃 처리

cy8erpsycho·2023년 9월 11일
0

스프링

목록 보기
27/29
post-thumbnail

로그인과 로그아웃 처리

접근 제한 설정

security-context.xml에 다음과 같이 접근 제한을 설정한다.

롤 단위의 권한 부여 : 관리자 권한은 관리자 역할을 하는 사람에게 부여한다.

	<security:http>
		<security:intercept-url pattern="/sample/all" access="permitAll"/> <!-- 모든사람들에게 허용 -->
		<security:intercept-url pattern="/sample/member" access="hasRole('ROLE_MEMBER')"/> 
		<security:form-login/>
	</security:http>
 	<security:authentication-manager>
 	
 	</security:authentication-manager>

특정한 URI에 접근할 때 인터셉터를 이용해서 접근을 제한하는 설정은
<security:intercept-url>을 이용한다.
pattern 속성 : URI의 패턴을 의미한다.
access 속성 : 권한을 체크한다.

이 페이지는 만든 적이 없는데 왜 나온거지? '/sample/member'를 접근하면 위와 같이 로그인 페이지로 강제 이동하는 것을 볼 수 있다.

모듈이 설치되어 제공되는 페이지이다. 시큐리티 모듈을 작성해서 넣은 결과이다. 핵심은 시큐리티 매니저가 인증과 권한부여에 대한 내부적 처리 수행함을 알 수 있다.

단순 로그인 처리

<security:authentication-manager>에서 설정을 한다. 추가적인 설정을 통해서 지정된 아이디와 패스워드로 로그인이 가능하도록 설정을 추가한다. 패스워드는 암호화가 되어야 한다. 하지만 지금은 연습이므로 패스워드를 평문의 형태로 작성하도록 한다.

 	<security:authentication-manager>
 		<security:authentication-provider>
 			<security:user-service>
 				<security:user name="member" 
                password="member" authorities="ROLE_MEMBER"/>
 			</security:user-service>
 		</security:authentication-provider>
 	</security:authentication-manager>

member는 ROLE_MEMBER라는 권한을 가진다는 의미이다.
member로 접근을 하면 허용이 되어야한다.

그런데 위에서 등록한 member를 입력하면 위와 같이 오류메세지가 뜬다.
왜 그럴까?
패스워드를 전달하기 위해서는 PasswordEncoder가 반드시 설정되어 있어야 한다. 패스워드가 있으면 패스워드에 특수한 함수를 돌리면 암호화된 문자열이 나온다. 이 암호화된 문자열을 SHA 알고리즘(해쉬함수)를 돌려서 나온다고 표현한다. 보통 128바이트로 암호화를 시킨다.

지금은, 패스워드를 인코딩하는 형태는 일방향이다.(쌍방향은 금지)
해쉬함수로 암호화를 하며, 128바이트 정도로 되어있다.(국제표준)

password="{noop}member" 이렇게 코드를 작성하면 인코딩을 하지말고 값을 전달하라는 뜻이다.

이제 로그인을 하면 회원만 볼 수 있는 페이지로 이동한다.
브라우저를 종료하고 다시 접속하면 로그인 페이지로 이동한다. 이는 이 역시 세션을 사용한다는 의미이다.

요청을 할때 Request Header부분에 쿠키를 같이 보낸다.

엣지에서 다시 요청을 하게되면 새로운 SessionId가 부여된다.

크롬에서는 기본적인 세팅이 세션이 공유되서 같은 페이지가 나오게 된다.

세션이 새로 만들어 질때

  • 쿠키의 세션아이디가 없이 요청이 왔을때
  • 세션아이디가 들어왔지만 서버측에서 그에 맞는 세션아이디 공간이 없을때

서버에서 세션공간이 사라질때

  • 세션 인밸리데이트(프로그래머가 강제적으로 삭제)
  • 세션 타임아웃(자연스럽게 세션 공간을 삭제)

세션아이디는 브라우저를 종료하기 전까지 쿠키메모리에 저장되서 서버에 계속 보내질수 있다.

로그아웃 확인

그럼 로그아웃은 어떻게 할까? 가장 무식한 방법은 Application에서 sessionID를 지우는 것이다. 그러나 이 방법은 서버 쪽에서는 sessionID 공간이 남아있다. 브라우저 상에서만 지워진 것이다.

여러 권한을 가지는 사용자 설정

클라이언트가 요청을 했지만, 권한이 없는 요청을 했다는 뜻이다.

<security:user name="admin" password="{noop}admin" authorities="ROLE_MEMBER, ROLE_ADMIN"/>
member에도 속하고 admin에도 속하게 코드를 작성한다.

접근 제한 메시지의 처리

특정한 사용자가 로그인은 했지만, URI를 접근할 수 있는 권한이 없는 상황이 발생할 수도 있다. 이 경우에는 접근 제한 에러 메시지를 보게 된다. member라는 권한을 가진 사용자는 '/sample/member'에는 접근할 수 있지만, '/sample/admin'은 접근할 수 없다. 이 경우에는 아래와 같은 메시지를 보게 된다.

이 Forbidden 페이지를 커스터마이징 할 수 있다. 스프링 시큐리티에서 접근 제한에 대해서 AccessDeniedHandler를 직접 구현하거나 특정한 URI를 지정할 수 있다.

<security:access-denied-handler error-page=""/>

위의 코드는 접근 제한이 일어나면 페이지를 이동한다는 의미이다.
코드를 작성할때 url이 나오면 이 페이지에 대한 컨트롤러가 당연히 추가 되어야 한다는것을 기억하자.

오류가 발생된 것의 인자가 위의 메서드에 들어간다!

@Controller
@Log4j
public class AccessDenyController {
	
	@GetMapping("/accessError")
	public void accessDenied(Authentication auth) {
		log.info("인증 : " + auth);
	}
}

위와 같이 코드를 작성한 후 member로 로그인 한 후 admin으로 접속하면 다음과 같은 내용이 콘솔에 뜬다.

INFO : com.zerock.controller.AccessDenyController - 인증 : org.springframework.security.authentication.UsernamePasswordAuthenticationToken@8f74b9: Principal: org.springframework.security.core.userdetails.User@bfc28a9a: Username: member; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_MEMBER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 1EBEA1261F4E81A76DDE161FC3E95D40; Granted Authorities: ROLE_MEMBER

jsp의 4단계 scope

Model은 request scope

getMessage() : 한줄로 간단하게
e.printstacktrace : 모든 정보를 다

만약 여기서 Model을 세션스코프로 바꾸면 어떻게 될까?

세션을 invalidate 하지 않는한 계속해서 유지해서 쓸수 있다.

위와 같이 jsp쪽에서 어느 스코프에서 찾을지 설정하면 시간을 단축할 수 있다.


커스텀 로그인 페이지

<security:form-login login-page="/customLogin"/>

url을 지정하는 형태니까 컨트롤러가 받아야 한다.

LoginController 생성하고 기본틀 작성한다.

@Controller	
@Log4j
public class LoginController {
	
	@GetMapping("/customLogin")
	public void loginInput() {
		
	}
}

void 타입이므로 veiw 작성한다.

0개의 댓글