# 스프링 시큐리티
### 라이브러리 추가
라이브러리를 추가합니다. **스프링 버전**에 의존도가 있으므로 의존성(dependency) 관련 버전 확인 후 사용하세요.
> **시큐리티 4.1.3**의 경우 요구되는 **스프링 버전은 4.3.2** 입니다.
**pom.xml**
```xml
<!-- Spring Security: web -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.1.3.RELEASE</version>
</dependency>
<!-- Spring Security: config -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.1.3.RELEASE</version>
</dependency>
<!-- Spring Security: taglibs -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>4.1.3.RELEASE</version>
</dependency>
```
### 설정파일 등록
스프링 시큐리티 설정파일을 등록합니다.
**web.xml**
```xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/root-context.xml
/WEB-INF/spring/security/security-context.xml
</param-value>
</context-param>
```
### 필터 추가
스프링 시큐리티 적용을 위해 필터를 추가합니다. 필터의 이름은 반드시 `springSecurityFilterChanin`이어야 합니다.
**web.xml**
```xml
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
```
### 스프링 시큐리티 설정파일
스프링 시큐리티 관련 설정을 합니다.
**/WEB-INF/spring/security/security-context.xml**
```xml
<?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:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<!-- 스프링 시큐리티 설정의 거의 모든 것 -->
<sec:http pattern="/css/**" security="none" />
<sec:http pattern="/img/**" security="none" />
<sec:http pattern="/js/**" security="none" />
<sec:http pattern="/uploads/**" security="none" />
<sec:http auto-config='true' use-expressions="true">
<sec:intercept-url pattern="/" access="permitAll" />
<sec:intercept-url pattern="/login" access="permitAll" />
<sec:intercept-url pattern="/**" access="isAuthenticated()" />
<sec:form-login login-page="/login"
login-processing-url="/user/login"
default-target-url="/"
username-parameter="username"
password-parameter="password"
authentication-failure-url="/login?error"
always-use-default-target='true' />
<sec:logout invalidate-session="true"
logout-url="/logout"
logout-success-url="/login?logout" />
<!-- enable csrf protection -->
<sec:csrf/>
</sec:http>
<sec:authentication-manager>
<sec:authentication-provider>
<sec:user-service>
<sec:user name="user" password="1234" authorities="ROLE_USER"/>
</sec:user-service>
</sec:authentication-provider>
</sec:authentication-manager>
</beans>
```
### 로그인 페이지 생성
로그인 페이지를 만듭니다.
**views/statics/login.jsp**
```jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page pageEncoding="utf-8" %>
<div class="jumbotron">
<h1>로그인</h1>
</div>
<form action="<c:url value='/user/login' />" method="post">
<div class="form-group form-group-lg">
<div class="form-group">
<label>사용자명</label>
<input type="text" name="username" class="form-control" placeholder="이메일">
</div>
<div class="form-group">
<label>비밀번호</label>
<input type="password" name="password" class="form-control" placeholder="비밀번호">
</div>
<div class="form-group">
<input type="hidden" name="${ _csrf.parameterName }" value="${ _csrf.token }" >
</div>
<div class="form-action">
<input type="submit" class="btn btn-primary btn-lg" value="로그인">
</div>
</div>
</form>
```
### 로그인 / 로그아웃 버튼 추가
네비게이션에 로그아웃 버튼을 추가합니다.
**tiles/components/header.jsp**
```jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://www.springframework.org/security/tags"
prefix="sec"%>
<%@ page pageEncoding="utf-8"%>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="#">Yes24</a>
<button class="navbar-toggler" type="button" data-toggle="collapse"
data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active"><a class="nav-link" href="#">도서<span
class="sr-only">(current)</span></a></li>
</ul>
<!-- 로그인 버튼 -->
<sec:authorize access="isAnonymous()">
<c:url var="loginUrl" value="/login" />
<ul class="nav navbar-nav navbar-right">
<li><a href="${ loginUrl }">로그인</a></li>
</ul>
</sec:authorize>
<!-- 로그아웃 버튼 -->
<sec:authorize access="isAuthenticated()">
<c:url var="logoutUrl" value="/logout" />
<form action="${logoutUrl}" method="post"
class="navbar-form navbar-right">
<button type="submit" class="btn btn-default">로그아웃</button>
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
</form>
</sec:authorize>
</div>
</nav>
```
### 컨트롤러 생성
SessionsController.java
```java
package com.mycompany.influencer;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class SessionsController {
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String login() {
return "statics/login";
}
}
```
로그인 페이지 접속 확인
![Imgur](https://i.imgur.com/bmENGj5.png)
### 테이블 생성
테이블명과 컬럼명은 기본적으로 지정하여 사용(필요시 커스터마이징 가능)
```
create table users (
id serial primary key,
email varchar(50) unique,
password varchar(100),
enabled boolean not null
);
insert into users (email, password, enabled)
values('
[email protected]', '1234', true);
```
```
create table authorities (
email varchar(50) not null,
authority varchar(50) not null
);
insert into authorities (email, authority)
values('
[email protected]', 'USER');
```
### 시큐리티 설정
사용자 인증을 DB로부터 받아오도록 함. 사용자 및 권한 관련 쿼리를 커스터마이징(기본값으로 users테이블은 username과 password를 컬럼값으로 사용하나 위에서 email과 password를 사용하였으므로 쿼리변경 필수!!)
**spring/security/security-context.xml**
```xml
<sec:authentication-manager>
<sec:authentication-provider>
<sec:jdbc-user-service data-source-ref="dataSource"
users-by-username-query="SELECT email, password, enabled FROM users WHERE email = ?"
authorities-by-username-query="SELECT email, authority FROM authorities WHERE email = ?" />
</sec:authentication-provider>
</sec:authentication-manager>
```
```xml
<sec:form-login login-page="/login"
login-processing-url="/user/login"
default-target-url="/"
username-parameter="email"
password-parameter="password"
authentication-failure-url="/login?error"
always-use-default-target='true' />
```
### 로그인 페이지
로그인 페이지 폼 데이터의 이름 또한 컬럼명에 맞게 변경
**views/statics/login.jsp**
```jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ page pageEncoding="utf-8"%>
<div class="jumbotron">
<h1>로그인</h1>
</div>
<div class="container">
<form action="<c:url value='/user/login' />" method="post">
<div class="form-group form-group-lg">
<div class="form-group">
<label>사용자명</label> <input type="text" name="email" class="form-control" placeholder="이메일">
</div>
<div class="form-group">
<label>비밀번호</label> <input type="password" name="password" class="form-control" placeholder="비밀번호">
</div>
<div class="form-group">
<input type="hidden" name="${ _csrf.parameterName }" value="${ _csrf.token }">
</div>
<div class="form-action">
<input type="submit" class="btn btn-primary btn-lg" value="로그인">
</div>
</div>
</form>
</div>
```