일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- Actor
- akka 강좌
- 파이썬 강좌
- 스위프트
- play 강좌
- 스칼라
- Play2 로 웹 개발
- 파이썬
- Golang
- 파이썬 머신러닝
- 하이퍼레저 패브릭
- CORDA
- 블록체인
- 파이썬 데이터분석
- 스칼라 동시성
- 플레이프레임워크
- Akka
- hyperledger fabric
- 그라파나
- 스칼라 강좌
- 파이썬 동시성
- 안드로이드 웹뷰
- 이더리움
- Adapter 패턴
- play2 강좌
- 엔터프라이즈 블록체인
- 하이브리드앱
- 주키퍼
- Hyperledger fabric gossip protocol
- Play2
- Today
- Total
HAMA 블로그
스프링 시큐리티 기초 따라가기 (1) - 환경설정 및 기본 로그인 시스템 본문
만들던 웹어플리케이션에 인증(로그인)기능을 추가하게되었다. 추가했던 과정을 그대로 보여주는 게시글이다.
15년전에 홈페이지 (디아블로2 펜페이지) 를 처음 개발 했었을때 로그인방식은 ID/PWD 를 FORM 기반으로
서버로 보내면 , 서버는 ID/PWD 를 확인하여 세션에 등록한후에, 요청이 오면 세션을 확인하여 존재하면 보여주고 ,
없으면 로그인창으로 리다이렉트 시켰던것으로 기억한다. 대규모 웹SI 개발을 해보지 않아서 요즘 트랜드가 어떤지 잘모르지만 스프링이 대세니깐 스프링 보안으로 해본다. :-) 프레임워크를 사용함으로써 고난이도의 구현 과 사상을 쉽게 가져다 쓸수있게 되었다.
이번 연재에서는 아래와 같은 기능을 추가할것이다.
1. 기본 환경설정 (POM.XML / WEB.XML / Security-context.XML )
2. 로그인 인증 시스템 (로그인페이지등 제작)
3. 인터셉터를 통한 권한 설정 (ROLE_USER)
3. DB 를 통한 사용자 정보 획득 기술
4. CSRF 보안
1. POM.XML 파일에 라이브러리를 추가.
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
설명)
스프링 시큐리티 3.2.3 을 추가하였다.
참고로 스프링이 3.1 버전일때 문제가 생겼다. 3.2 이상으로 올려야한다. 이런 의존성 문제 때문에 한참을 고생했다.
2. WEB.XML 수정
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/root-context.xml
/WEB-INF/spring/security-context.xml <--- 추가
</param-value>
</context-param>
<!-- Security filter 추가 -->
<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>
설명)
스프링이 시큐리티 관련 설정을 읽어가도록 security-context.xxml 을 추가 해주며
필터도 추가해주자. 유의사항은 필터 이름은 springSecurityFilterChain 이어야만 한다.
3. security-context.xml 파일 추가
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<http auto-config='true' use-expressions="true"> ---------- (1)
<intercept-url pattern="/login" access="permitAll" /> ---------- (2)
<intercept-url pattern="/resources/**" access="permitAll" /> ---------- (3)
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" /> ---------- (4)
<form-login login-page="/login" ---------- (5)
default-target-url="/monitering" ---------- (6)
username-parameter="username" ---------- (7)
password-parameter="password" ---------- (8)
authentication-failure-url="/login?error" --------- (9)
always-use-default-target='true' --------- (10)
/>
<logout invalidate-session="true" logout-url="/logout" logout-success-url="/login?logout" /> - (11)
<!-- enable csrf protection -->
<csrf/> ---------- (12)
</http>
<authentication-manager> ---------- (13)
<authentication-provider user-service-ref="memberService"/> ---------- (14)
</authentication-manager>
<beans:bean id="memberService" class="com.company.wmos.auth.MemberService"> ---------- (15)
</beans:bean>
</beans:beans>=
설명)
(1) auto-config='true' 를 설정한것만으로 기본 로그인페이지/ HTTP 기본인증 / 로그아웃기능등을 제공한다.
use-expressions="true" 는 SpEL 을 사용한다는 의미이다.
- use-expressions="true"를 설정하지 않으면 default 가 false 이다. 이럴때는 SpEL을 사용하지 않는다.
<http auto-config="true">
<intercept-url pattern="..." access="ROLE_ANONYMOUS" />
<intercept-url pattern="..." access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="..." access="ROLE_USER" />
<intercept-url pattern="..." access="ROLE_ADMIN" />
</http>
- use-expressions="true" 로 설정하면 SpEL을 사용해서 작성을 해야한다. 그렇지 않으면 에러가 발생한다.
<http auto-config="true" use-expressions="true">
<intercept-url pattern="..." access="permitAll" />
<intercept-url pattern="..." access="hasRole('ROLE_ANONYMOUS')" />
<intercept-url pattern="..." access="hasRole('ROLE_USER')" />
<intercept-url pattern="..." access="hasRole('ROLE_ADMIN')" />
</http>
(2)~(4)해당 URL 에 접근하기위한 권한을 설정하여준다. ( 접근가능한 IP 등을 설정할수도있다) . 그리고 권한은 위쪽이 우선시된다.
(2) /login 으로는 모두 허용해준다./login 을 막아놓으면 안되니깐~
(3) 리소스도 허용해주고
(4) 나머지는 모두 ROLE_USER 권한을 가진사람만 허용해준다.
(5) <form-login 사용자이름과 비밀번호를 가지고있는 폼기반 인증방법을 사용한다.
login-page="/login" 를 설정하여 사용자가 만든 로그인페이지를 스프링에게 알려준다.
이거 설정안하면 스프링이 만들어준것을 사용.
(6) default-target-url="/monitering" 로그인성공하면 이동할 페이지설정
(7) (8) 이거 설정안해도 된다. 나중에 long.jsp 페이지에서 FORM 안에 들어갈 name 을 여기서 지정한것으로 바꾸어준다.
(9) authentication-failure-url="/login?error" 실패시 호출해줄 URL (login 페이지에 error 파라미터를 보내준다)
(10) always-use-default-target='true' 이거 안하면 로그인성공해도 /monitering 로 제대로 안가더라
(11) 로그아웃되면 세션을 초기화한다.
logout-success-url="/login?logout" <-- 로그아웃되면 이동할 페이지
logout-url="/logout"<--로그아웃을 위한 URL설정. 이거 안해주면 디폴트로 j_spring_security_logout 해주면됨.
(12) 간단한 설정으로 csrf 를 통한 해킹을 막을수있다.
( CSRF 설명: http://tm-csc.tistory.com/entry/7-WebHacking%EC%9B%B9%ED%95%B4%ED%82%B9-CSRF)
(13) 인증처리를 위한 최상위 태그
(14) user-service-ref="memberService" 사용자이름/비밀번호를 제공해줄 서비스 등록
이 게시물에서는 DB 를 이용하여 처리하려고하는데, 인메모리로 바로 적어줄수도있다. 다음처럼
<authentication-manager> <authentication-provider> <user-service> <user name="admin" password="1234" authorities="ROLE_USER" /> </user-service> </authentication-provider> </authentication-manager>
(15) MemberService 빈등록
HTTP 기본인증이란 ?
위와 같은 폼 기반 인증은 애플리케이션 사용자가 사람일때 이상적이지만 , 사용자가 다른 애플리케이션이라면 폼로그인을 사용하지 못할수도있다.
HTTP 기본인증은 HTTP 요청 시 사용자가 직접 어플리케이션에 대해 인증하는 방법이다. 웹 브라우저에서 HTTP 기본인증을 접하면 단순한 모달 대화상자로 사용자에게 입력을 요청한다. 이것은 실제로는 사용자명과 패스워드가 필요하다는 HTTP 401 응답이다. 이러한 HTTP 기본 인증은 REST 클라이언트가 사용하는 서비스의 인증 수단으로 적합하다.
따라서 로그인으로 인증에 성공하면 인증정보가 클라이언트에 저장되어서 후속 요청시에 서버로 HTTP 프로토콜에 뭍어서 날라올거라는것을 알수가 있다. 그 사용자 정보(롤포함) + 요청URL 의 권한정보를 토대로 접근을 허용할지 안할지 결정할수있을것이라 생각된다.
4. 컨트롤러 추가
package com.company.wmos.auth;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class authController {
private static final Logger logger = LoggerFactory.getLogger(authController.class);
@RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView login(
@RequestParam(value = "error", required = false) String error,
@RequestParam(value = "logout", required = false) String logout) {
ModelAndView model = new ModelAndView();
if (error != null) {
model.addObject("error", "Invalid username and password!");
}
if (logout != null) {
model.addObject("msg", "You've been logged out successfully.");
}
model.setViewName("login");
return model;
}
}
package com.company.wmos.auth;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import com.company.wmos.model.UserVO;
import com.company.wmos.service.UserService;
public class MemberService implements UserDetailsService{
@Autowired UserService userService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserVO userVO = userService.getUsersByID(username);
if (userVO == null) {
throw new UsernameNotFoundException("No user found with username" + userVO.getName());
}
Collection<SimpleGrantedAuthority> roles = new ArrayList<SimpleGrantedAuthority>();
roles.add(new SimpleGrantedAuthority("ROLE_USER"));
UserDetails user = new User(username, userVO.getPassword(), roles);
return user;
}
}
<body ng-controller="moniteringCtrl" class="pad">
<c:url value="/logout" var="logoutUrl" />
<!-- csrt for log out-->
<form action="${logoutUrl}" method="post" id="logoutForm">
<input type="hidden"
name="${_csrf.parameterName}"
value="${_csrf.token}" />
</form>
<script>
function formSubmit() {
document.getElementById("logoutForm").submit();
}
</script>
<!------------------------ navigation ------------------------>
....
<form class="navbar-form navbar-right" >
<span style="color: gray;" ><h5> ${username} 님 반갑습니다.
<a href = "javascript:formSubmit()"> 로그아웃 </a> </h5></span>
</form>
....
이거 안해주면 디폴트로 j_spring_security_logout 해주면됨.
- 로그인 실패시 -
- Monitering 페이지 -
- 로그아웃 화면-
'Spring' 카테고리의 다른 글
스프링 시큐리티 기초 따라가기 (3) - HTTPS (0) | 2015.07.15 |
---|---|
스프링 시큐리티 기초 따라가기 (2) - Remember Me (0) | 2015.07.14 |
Angular JS and Spring Security 1 ~4 편 (번역) (0) | 2015.07.11 |
Mybatis-spring 버전별 의존성 요구사항 (0) | 2015.07.10 |
component-scan / annotation-config / annotation-driven 차이점 (2) | 2015.07.09 |