본문 바로가기
  • 실행력이 모든걸 결정한다
Spring Series/Spring Framework

[Spring] Spring Security(2) - 로그인 페이지 구현

by 김코더 김주역 2021. 1. 20.
반응형

Spring Security(1) 포스팅에서는 spring security에서 제공하는 로그인 페이지로 인증 절차를 거칠 수 있었다.

kimcoder.tistory.com/244

 

[Spring] Spring Security(1) - 기본 사용법

만약 관리자 페이지처럼 특정 계정으로만 접근 해야하는 페이지를 만들어야 한다면 어떻게 할까? 이번 포스팅에서 다룰 Spring Security를 사용한다면 이 궁금증을 해결할 수 있다. 이제 사용법을

kimcoder.tistory.com

 

이번 포스팅에서는 직접 만든 로그인 페이지를 security 로그인 페이지로 적용시키는 방법을 소개한다.

 

먼저, 예제로 사용한 프로젝트 구성은 이렇다

 

1. 로그인 페이지 만들기

<login.jsp>

user, password를 입력받아 <form>을 이용하여 login_check 경로로 전송한다.

user, password를 입력받는 <input>의 name은 각각 user_id, user_pw로 했다.

c:if 부분은 로그인에 오류가 생겼을 때 오류 메세지를 출력해주고, CSS를 이용하여 오류 메세지는 빨간 색으로 출력되게 했다. (sample.css)

<sample.css>

@charset "EUC-KR";
p {
color : red;
}

ng에 대한 설명은 잠시후에 하기로 한다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<link rel="stylesheet" href="/demo/resources/sample.css">
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>LOGIN</h1>
	<form action="login_check" method="post">
		<c:if test="${param.ng!=null}">
			<p> error : <c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}"/> </p>
		</c:if>
		USER : <input type="text" name="user_id"><br>
		PASSWORD : <input type="password" name="user_pw"><br>
		<input type="submit" value="Login">
	</form>
</body>
</html>

 

2. 직접 만든 로그인 페이지 접근을 위한 설정

<servlet_context.xml>, <web.xml>

Spring Security(1) 포스팅과 동일함

 

<HomeController.java>

잠시후 로그아웃도 다룰 것인데 로그아웃 후에 홈 화면으로 무사히 이동할 수 있게 home 매핑 메소드를 추가했다.

그리고 직접 만든 로그인 페이지에 접근할 수 있게 login 매핑 메소드도 추가했다.

package com.example.demo;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * Handles requests for the application home page.
 */
@Controller
public class HomeController {
	
	@RequestMapping("/index.html")
	public String home(Model model) {
		return "home";
	}
	
	@RequestMapping("/vip.html")
	public String vip(Model model) {
		return "vip";
	}
	
	@RequestMapping("/admin.html")
	public String admin(Model model) {
		return "admin";
	}
	
	@RequestMapping("/login.html")
	public String login(Model model) {
		return "login";
	}
}

 

 

<security_context.xml>

개발자가 만든 로그인 페이지를 적용하기 위해 s:form-login 설정을 추가했고, 로그아웃도 구현하기 위해 s:logout 설정도 추가했다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:s="http://www.springframework.org/schema/security"
	xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

	<s:http auto-config="true" use-expressions="true">
		<s:form-login
			username-parameter="user_id"
			password-parameter="user_pw"
			login-processing-url="/login_check" 
			login-page="/login.html" 
			authentication-failure-url="/login.html?ng"
		/>
		<s:logout 
			logout-url="/security_logout"
			logout-success-url="/"
			invalidate-session="true"
			delete-cookies="true"
		/>
		<s:intercept-url pattern="/login.html*" access="isAnonymous()"/>
		<s:intercept-url pattern="/vip.html*" access="hasRole('ROLE_USER')"/>
		<s:intercept-url pattern="/admin.html*" access="hasRole('ROLE_ADMIN')"/>
		<s:access-denied-handler error-page="/"/>
	</s:http>
		
	<s:authentication-manager>
		<s:authentication-provider>
			<s:user-service>
				<s:user name="codelove" password="1365" authorities="ROLE_USER"/>
				<s:user name="kimcoder" password="1366" authorities="ROLE_USER, ROLE_ADMIN"/>
			</s:user-service>
		</s:authentication-provider>
	</s:authentication-manager>
	
</beans>

* form-login의 속성 설명

1) username-parameter : 로그인 페이지에서 입력한 USER(input)에 대한 parameter name.

생략 시 기본값은 "j_username"

2) password-parameter : 로그인 페이지에서 입력한 PASSWORD(input)에 대한 parameter name.

생략 시 기본값은 "j_password"

3) login-processing-url : 로그인 페이지의 form에서 설정한 전송 주소(form의 action속성).

생략 시 기본값은 "/j_spring_security_check"

4) login-page : Controller로 보낼 로그인 페이지 주소

5) authentication-failrue-url : 로그인 실패 시 이동할 페이지. 아래 소스 코드같은 경우에는 "/login.html" 뒤에 "?ng"를 붙여서 오류 페이지임을 나타낸다. 오류가 나면, login.jsp에서 이 ng를 받아서 해당 오류 메세지를 출력하게 되는 것이다.

6) default-target-url : 로그인에 성공했을 때 보내줄 페이지. 생략 했을 시 사용자의 요청 경로로 이동한다.

 

* logout의 속성 설명

1) logout-url : 로그아웃 요청 주소. 생략 시 기본값은 "/j_spring_security_logout"

2) logout-success-url : 로그아웃 성공 시 이동할 페이지

3) invalidate-session : 세션 삭제 여부

4) delete-cookies : 쿠키 삭제 여부

 

 

3. 로그 아웃

세션을 지워서 클라이언트를 홈 화면으로 돌려보내는 작업이다.

 

<home.jsp>

HOME! 문구만 출력되는 홈 화면이다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1> HOME! </h1>
</body>
</html>

 

 

<vip.jsp>

c:if 부분은 로그인 세션이 남아있는지 여부를 판단한다. 페이지에서 로그인/로그아웃 부분을 다르게 구현 해야 할 때 유용하다.

${pageContext.request.userPrincipal.name} 은 로그인 페이지에서 USER에 입력한 값이다.

자신이 잘 로그인 되어있는지 확인하려는 용도이다.

그리고 ${pageContext.request.contextPath} 는 여러분들의 프로젝트의 contextPath 가 출력되며,

<a> 태그의 링크인 /demo/security_logout로 접근하면 세션, 쿠키가 사라지며 정상적으로 로그아웃 된다. security-context.xml에서 세션, 쿠키 삭제 여부는 모두 true로 설정했기 때문이다.

<%@ page language="java" contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1> FOR VIP MEMBERS! </h1>
	<c:if test="${not empty pageContext.request.userPrincipal}">
		<p> Session On </p>
	</c:if>
	<c:if test="${empty pageContext.request.userPrincipal}">
		<p> Session Out </p>
	</c:if>
	<p> HELLO ${pageContext.request.userPrincipal.name} </p>
	<a href="${pageContext.request.contextPath}/security_logout">Log Out</a>
</body>
</html>

 

 

<admin.jsp>

admin 페이지에도 세션 및 회원 확인, 로그아웃 기능을 추가한다.

단, 이번에는 다음과 같이 security 태그 방식을 사용했다.

Spring Security(1) 포스팅에서 설명했던 access 표현식을 이용하여 조건에 따라 Session On/Off를 출력시키도록 했다. 

두 방법 모두 출력 결과는 일치하기 때문에 편한 방식을 고르면 된다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://www.springframework.org/security/tags" prefix="s" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1> FOR ADMIN! </h1>
	<s:authorize access="isAuthenticated()">
		<p> Session On </p>
	</s:authorize>
	<s:authorize access="isAnonymous()">
		<p> Session Off </p>
	</s:authorize>
	<p> HELLO <s:authentication property="name"/> </p>
	<a href="${pageContext.request.contextPath}/security_logout">Log Out</a>
</body>
</html>

 

 

4. 실행

/demo/admin.html로 요청하여 로그인하고, 관리자 페이지로 접근하고, 로그아웃까지 마쳐보자.

 

1) /demo/admin.html로 요청하여 우리가 직접 만든 로그인 페이지가 나온 모습이다.

최초 요청이라 param.ng에 아무런 정보가 없기 때문에(null) 에러 메시지는 출력되지 않는다.

 

2) username 또는 password가 틀리다면 에러 메시지가 출력된다.

 

3) 로그인에 성공하여 admin.jsp 페이지로 접근 성공했다.

 

4) 로그아웃을 눌러서 세션이 지워졌으며, 홈 화면으로 무사히 되돌아갔다.

 

5) 세션이 지워졌기 때문에 /demo/admin.html로 다시 요청했을 때 로그인이 풀린 모습이다.

※ 서버를 재시작해도 세션이 지워진다.

 

 

다음 포스팅에서는 아이디, 비밀번호, 권한 설정을 security 설정 파일에 직접 작성하지 않고, Spring Security와 데이터베이스를 연동하여 로그인하도록 하는 방법에 대해 다룰 것이다.

kimcoder.tistory.com/248

 

[Spring] Spring Security(3) - DB연동

Spring Security(1), (2)에서는 아이디, 비밀번호, 권한 설정을 security 설정 파일에 직접 작성했다. kimcoder.tistory.com/245 [Spring] Spring Security(2) - 로그인 페이지 구현 Spring Security(1) 포스팅에..

kimcoder.tistory.com

 

 

반응형

'Spring Series > Spring Framework' 카테고리의 다른 글

[Spring] Spring Security(3) - DB연동  (0) 2021.02.01
[Spring] Mybatis  (0) 2021.01.26
[Spring] Spring Security(1) - 기본 사용법  (0) 2021.01.19
[Spring] JDBC 트랜잭션  (0) 2021.01.14
[Spring] JdbcTemplate  (0) 2021.01.11

댓글