728x90
반응형

스프링 시큐리티는 스프링 프레임워크의 하위 프로젝트로 웹 보안에 관련된 프레임워크입니다.

 

스프링 시큐리티의 보안 방법은 권한인증(Authentication)과 권한허가(Authorization)으로 이루어지는데,

 

사용자가 아이디와 비밀번호를 입력하여 매칭되는지 확인하고, 그 허가가 떨어지면 사용자는 그 인증된 데이터로 계속 보안을 유지하며

 

인증을 계속하게 됩니다.

 

스프링 시큐리티가 나온지는 꽤 오랜 시간이 지났지만, 국내에는 그다지 유명하지 않고 소개되어 있는 곳도 많지 않습니다. 따라서 간단한

 

따라하기 문서를 만들며 소개를 해보도록 하겠습니다. 여기서 소개되는 기능은 첫번쨰에서는 최소한의 기능만을 가지고 구현까지만 할 것이고,

 

계속 챕터를 나아가면서 기능을 덧붙여가기로 합시다.

 

 

 

1. 환경구성을 위한 파일 받기

 

우선 파일을 받아야합니다.

 

2013년 5월 29일 기준으로 스프링은 4.0이 출시되어있고, 시큐리티는 3.2 버전이 출시되어있습니다.

 

하지만 스프링 4.0은 아직 써보지도 못했으니 그 바로 전버전인 3.2.3 버전으로 작업을 하겠습니다.

 

스프링은 아래주소에서 받을 수 있습니다. 메이븐을 사용한다면 아래의 dependency를 추가하면 됩니다.

 

http://repo.springsource.org/libs-release-local/org/springframework/spring/3.2.3.RELEASE/spring-framework-3.2.3.RELEASE-dist.zip

<repository>

<id>springsource-repo</id>

<name>SpringSource Repository</name>

<url>http://repo.springsource.org/release</url>

</repository>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

<version>3.2.3.RELEASE</version>

</dependency>

 

스프링 시큐리티는 아래에서 받을 수 있습니다.

http://repo.springsource.org/libs-milestone-local/org/springframework/security/spring-security/3.2.0.M1/spring-security-3.2.0.M1-dist.zip

<dependency>

<groupId>org.springframework.security</groupId>

<artifactId>spring-security-core</artifactId>

<version>3.1.4.RELEASE</version>

</dependency>

<dependency>

<groupId>org.springframework.security</groupId>

<artifactId>spring-security-web</artifactId>

<version>3.1.4.RELEASE</version>

</dependency>

<dependency>

<groupId>org.springframework.security</groupId>

<artifactId>spring-security-config</artifactId>

<version>3.1.4.RELEASE</version>

</dependency>


 

그 이외에도 스프링과 기타 환경설정을 구성하기 위해 아래의 파일들을 추가로 등록했습니다.

 

commons-dbcp-1.2.2.jar

commons-logging-1.1.1.jar

commons-pool-1.3.jar

aopalliance-1.0.jar //트렌젝션을 위해 등록

jstl-1.2.jar //리졸버 뷰를 위해 등록

sqljdbc4.jar //mssql의 jdbc를 위해 등록

 

 

2. DB구조 설정


DB는 최소한의 기능만 담아서 아래와 같이 설정했습니다.

 

userId를 Key로 삼아 권한을 부여 할 것입니다.. 권한은 한 사람이 여러개를 가질 수 있으므로 1:N 으로 만들었습니다.

 

password는 시큐리티 자체에서 암호화하는 것을 권고하고 있으므로 크기를 넉넉하게 선언하는게 좋습니다.

 

permit은 승인 여부를 설정하는 것입니다. 1, 0 으로 boolean처럼 설정하면 됩니다.

 

3. 스프링과 시큐리티의 환경설정

 

본격적으로 새 웹 프로젝트를 만들고 시작해봅시다.

 

새 웹 프로젝트를 제작 했다면, web.xml 부터 설정해봅시다.

스프링 시큐리티는 FilterChain을 통해서 서블릿에서 넘어온 데이터들을 필터링합니다. 그러니 우선 이 설정을 추가합시다.

<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-servlet.xml , 시큐리티는 security-context 라고 쓰겠습니다.

 

이 두 파일도 서블릿에 맵핑시켜줘야 하므로 web.xml에 어디있는지 알려줄 설정을 써넣습니다.

 

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>

/WEB-INF/spring-servlet.xml

/WEB-INF/security-context.xml

</param-value>

</context-param>

<listener>

<listener-class>

org.springframework.web.context.ContextLoaderListener

</listener-class>

</listener>

<servlet>

<servlet-name>spring</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>spring</servlet-name>

<url-pattern>*.do</url-pattern>

</servlet-mapping>

 

 

다음은 spring-servlet 에 대한 설정입니다. 뷰 리졸버의 패턴을 설정하고, db를 설정합니다. 여기선 mssql 2008을 사용했으므로 각자의

 

db에 맞춰서 설정을 바꾸면 됩니다. 또한 트렌젝션을 이용하기 위해서 트렌젝션을 위한 설정도 써주었습니다.

 

<?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:p="http://www.springframework.org/schema/p"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:tx="http://www.springframework.org/schema/tx"

xmlns:mvc="http://www.springframework.org/schema/mvc"

xmlns:aop="http://www.springframework.org/schema/aop"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd

http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd

http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

 

<!-- example 패키지의 빈을 자동으로 생성 -->

<context:component-scan base-package="com.springSec" />

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">

<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>

<property name="prefix" value="/WEB-INF/view/" />

<property name="suffix" value=".jsp"></property>

</bean>

 

<!-- mssql-->

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">

<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>

<property name="url" value="jdbc:sqlserver://localhost:1433;selectMethod=cursor;"/>

<property name="username" value="userid"/>

<property name="password" value="password"/>

</bean>

<!-- 트랜잭션 매니저 -->

<bean id="transactionManager"

class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dataSource"/>

</bean>

 

<!-- Annotation 기반 트랜잭션 설정 -->

<tx:annotation-driven transaction-manager="transactionManager" />

</beans>

 

 

제일 중요한 security-context의 설정입니다. 좀 기니 세토막으로 잘라서 설명하겠습니다.

 

1. <Http>

 

http 안에서는 주소에 대한 설정을 가집니다. 주로 주소를 가로채는 intercept를 설정하여 권한에 맞지 않으면 튕겨내는 기능을 합니다.

 

use-expressions : intercept-url의 access에 spring EL을 사용. 예를 들면 hasAnyRole() 과 같은 것들

(자세한 내용은 여길 참고 http://blog.naver.com/platinasnow/30168908884 )

 

intercept-url : 해당주소에 어떤 권한을 가진 사람을 접근시킬 것인가에 대한 설정을 할 수 있음. 더불어 Handler를 설정하여 intercept

했을 때 추가 설정을 해줄 수도 있음.

 

access="permitAll : 같은 경우는 모든 권한을 전부 접근 허락하겠다는 의미

 

access="hasAnyRole()" : () 안의 권한만 허락하겠다는 의미

 

login-page : 로그인을 할 페이지를 설정

 

default-target-url : intercept 당했을 때 돌아가는 주소이다.

 

logout invalidate-session : 로그아웃 했을 때 세션을 비움

 

logout-url : 로그아웃을 시킬 주소

 

logout-success-url :로그아웃이 성공하면 보내질 페이지

 

<?xml version="1.0" encoding="UTF-8"?>

<beans:beans xmlns="http://www.springframework.org/schema/security"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd

http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

 

<http auto-config="true" use-expressions="true">

<intercept-url pattern="/loginPage.do" access="permitAll" />

<intercept-url pattern="/makeAccount.do" access="permitAll" />

<intercept-url pattern="/makeAccountSubmit.do" access="permitAll" />

<intercept-url pattern="/**.do" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')" />

<form-login login-page="/loginPage.do" default-target-url="/loginPage.do"/>

<logout invalidate-session="true" logout-url="/logout.do" logout-success-url="/loginPage.do" />

</http>

 

 

 

2. <authentication-manager>

 

authentication-manager에는 로그인하는 정보들이 넘어오는 곳입니다.

 

authentication-provider user-service-ref 에는 3. 에서 만든 securityService 라는 bean을 주입하여 로그인 정보를 처리 할 것 입니다.

 

password-encoder는 비밀번호를 암호화 하는 것입니다. 여기에서는 passwordEncode bean을 선언하여 sha 방식으로 인코딩했습니다.

 

<authentication-manager>

<authentication-provider user-service-ref="securityService" >

<password-encoder ref="passwordEncoder" />

</authentication-provider>

</authentication-manager>

<beans:bean id="passwordEncoder"

class="org.springframework.security.authentication.encoding.ShaPasswordEncoder"/>

 

3. securityService

 

로그인 정보를 처리하기 위해서 만든 bean입니다. 따로 튜닝을 하지 않고 시큐리티에서 지원하는 JdbcDaoImpl을 가지고 db 쿼리만 주입해서

 

진행하도록 하겠습니다. spring-servlet에서 설정한 datasource를 주입하여 usersByUsernameQuery에 아이디, 비밀번호, 접속허가 순서로 쿼리를

 

넣어줍니다. 아래의 authoritiesByUsernameQuery 에서는 저장된 권한을 불러오는 쿼리를 작성하면 됩니다. 아이디, 권한 순으로 짜면 되겠습니다.

 

<beans:bean id="securityService"

class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">

<beans:property name="dataSource" ref="dataSource" />

<beans:property name="usersByUsernameQuery">

<beans:value>

SELECT userid,password,permit

FROM

UserTable

WHERE userid=?

</beans:value>

</beans:property>

<beans:property name="authoritiesByUsernameQuery">

<beans:value>

SELECT userId,authority

FROM Authorities

WHERE userId = ?

</beans:value>

</beans:property>

</beans:bean>

</beans:beans>

 

 

4. 컨트롤러, DAO, 뷰

 

이제 거의 끝났습니다. 그럼 우선 로그인페이지와 아이디 생성페이지를 위한 뷰를 위한 컨트롤러를 설정합시다.

 

여기서 makeAccount.do , makeAccountSubmit.do 는 위의 intercept-url 에서 열어준 페이지이므로 다른 페이지에 접근이 안된다고 이상하게

 

생각하지 맙시다. 다른 페이지에 접근하려면 페이지에 맞게 권한을 열어줘야 합니다.

@Autowired

private LoginDao loginDao;

@RequestMapping("/loginPage.do")

public String loginPage(Model model){

return "loginPage";

}

@RequestMapping("/logout.do")

public String logout(Model model){

return "redirect:index.do";

}

@RequestMapping("/makeAccount.do")

public String makeAccount(Model model){

return "makeAccount";

}

@RequestMapping("/makeAccountSubmit.do")

public String makeAccountSubmit(String userId, String password){

loginDao.makeAccount(userId, password);

return "redirect:loginPage.do";

}

 

 

Dao는 스프링에서 지원하는 JdbcDaoSupport를 사용해서 간단하게 만들었습니다. 비밀번호를 Insert 할 때 sha방식으로 인코딩해서 집어넣는 것에

 

유의합시다.

 

@Autowired

private JdbcDaoSupport daoSupport;

@Autowired

private PasswordEncoder passwordEncoder;

 

private void insertUser(String userId, String password) {

String sql="use praline " +

"INSERT INTO UserTable(userId, password, permit) "+

"VALUES(?, ?, 1)";

daoSupport.getJdbcTemplate().update(sql, userId, passwordEncoder.encodePassword(password, null));

}

 

private void insertAuthority(String userId) {

String sql="use praline " +

"INSERT INTO Authorities(userid, authority) "+

"VALUES(?, ?)";

daoSupport.getJdbcTemplate().update(sql.toString(), userId, "ROLE_USER");

}

@Transactional

public void makeAccount(String userId, String password) {

insertUser(userId, password);

insertAuthority(userId);

}

 

 

마지막으로 로그인 페이지 뷰입니다.

 

스프링 시큐리티에 의해서 id는 name을 j_username으로 하여 전송 해야하고, password는 j_password를 써야합니다.

 

그리고 로그인 도착지점(action)은 j_spring_security_check로 해야합니다.

 

로그인에 성공하면 <sec:authentication property="Authorities" /> 에 의해서 지금 현재 가지고 있는 권한이 나오게 됩니다.

 

로그인 하지 않았다면 [ROLE_ANONYMOUS]가 나오게 될 것입니다.

 

<%@ page language="java" contentType="text/html; charset=EUC-KR"

pageEncoding="EUC-KR"%>

<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

<body>

<form id="loginForm" method="post" >

<p><input type="text" name="j_username" placeholder="ID" required/></p>

<p><input type="password" name="j_password" placeholder="Password" required/></p>

<Button type="button" onclick="login()" >로그인</Button>

<Button type="button" onclick="logout()" >로그아웃</Button>

<Button type="button" onclick="makeAccount()">아이디 만들기</Button>

<div>

<sec:authentication property="Authorities"/>

</div>

</form>

</body>

<script type="text/javascript">

var loginForm = document.getElementById('loginForm');

function login(){

loginForm.action = "j_spring_security_check";

loginForm.submit();

}

function logout(){

loginForm.action = "logout.do";

loginForm.submit();

}

function makeAccount(){

loginForm.action = "makeAccount.do";

loginForm.submit();

}

</script>

 

 

이걸로 간단하게 스프링 시큐리티가 적용 되기한 소스가 완성되었습니다. 하지만 이는 스프링 시큐리티의 기능을 최소한으로

사용한 것으로 더 많은 기능들이 있습니다. 앞으로는 이런 기능들을 조금씩 꺼내보겠습니다..

 

소스코드는 여기에 올려놓았으니 참고해도 좋습니다.

 

https://github.com/praline0/SpringSecurityExample.git

 

728x90
반응형
블로그 이미지

nineDeveloper

안녕하세요 현직 개발자 입니다 ~ 빠르게 변화하는 세상에 뒤쳐지지 않도록 우리모두 열심히 공부합시다 ~! 개발공부는 넘나 재미있는 것~!

,