[spring] Spring Security 인증 구현
작성일자 : 2018년 10월 18일
환경 : Spring Framework 3.1.1, Spring Security 3.1.3
설정 위치 :
1. pom.xml
<dependencies> ... <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>3.1.3.RELEASE</version> </dependency>
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>3.1.3.RELEASE</version> </dependency> ... </dependencies> |
프로젝트 내에서 Spring Security를 사용하기 위한 의존성 추가
2. web.xml
<web-app> ... <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> .. .. <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-app> |
모든 경로에 filter 추가, context 등록
3. User.java
package com.company.security; import java.util.Collection; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; public class User implements UserDetails{ private static final long serialVersionUID = 1L; private String id; private String pw;
public String getId() { return id; } public void setId(String id) { this.id = id; } public String getPw() { return pw; } public void setPw(String pw) { this.pw = pw; }
@Override public Collection<? extends GrantedAuthority> getAuthorities() { // TODO Auto-generated method stub return null; } @Override public String getUsername() { // TODO Auto-generated method stub return null; } @Override public boolean isAccountNonExpired() { // TODO Auto-generated method stub return false; } @Override public boolean isAccountNonLocked() { // TODO Auto-generated method stub return false; } @Override public boolean isCredentialsNonExpired() { // TODO Auto-generated method stub return false; } @Override public boolean isEnabled() { // TODO Auto-generated method stub return false; } @Override public String getPassword() { // TODO Auto-generated method stub return null; } } |
Spring Security의 UserDetails을 구현한 클래스, 유저 세션 객체로서 사용
4. CustomAuthenticationProvider
package com.company.security; import java.util.ArrayList; import java.util.List; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import com.company.security.User; public class CustomAuthenticationProvider implements AuthenticationProvider { @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String user_id = (String)authentication.getPrincipal(); String user_pw = (String)authentication.getCredentials(); // Form에서 전달 된, name 태그 설정이 username-parameter, password-parameter로 되있는 값을 읽어온다
if(user_id.equals("fail")){ return null; } //fail로 로그인 시 null 반환 > loginFail 테스트 // ---------------------------------------------- // DB 내 아이디, 패스워드 값 비교 로직 필요 // ---------------------------------------------- User user= new User(); user.setId(user_id); user.setPw(user_pw); List<GrantedAuthority> roles = new ArrayList<GrantedAuthority>(); roles.add(new SimpleGrantedAuthority("ROLE_USER")); UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(user_id, user_pw, roles); result.setDetails(user); //user session 생성 후 반환
return result; } @Override public boolean supports(Class<?> authentication) { return authentication.equals(UsernamePasswordAuthenticationToken.class); }
} |
Spring Security의 AuthenticationProvider을 구현한 클래스로 security-context에 provider로 등록 후 인증절차를 구현
login view에서 login-processing-url로의 form action 진행 시 해당 클래스의 supports() > authenticate() 순으로 인증 절차 진행
5. 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.1.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<http pattern="/resources/**" security="none"></http> <http pattern="/**/login" security="none"></http> <http pattern="/**/loginFail" security="none"></http> <http auto-config='true'> <intercept-url pattern="/**" access="ROLE_USER" /> <form-login login-page="/login" username-parameter="id" password-parameter="pw" login-processing-url="/login.do" default-target-url="/loginSuccess" authentication-failure-url="/loginFail" always-use-default-target='true' /> </http>
<authentication-manager> <authentication-provider ref="customAuthenticationProvider" /> </authentication-manager> <beans:bean id="customAuthenticationProvider" class="com.company.security.CustomAuthenticationProvider"/> </beans:beans> |
Spring Security 설정
<http pattern="/**/login" security="none"></http> : 특정 url의 security 제외, 해당 URL로는 인증 절차 없이도 접근 가능
login-page : 로그인 URL
username-parameter, password-parameter : 아이디, 비밀번호로 사용할 변수 명
login-processing-url : 인증 절차를 진행 할 URL, 해당 URL로 form 전송 시 AuthenticationProvider을 구현한 클래스로 전달
default-target-url : 성공 시 이동
authentication-failure-url : 실패 시 이동
<authentication-provider ref="customAuthenticationProvider" /> : AuthenticationProvider을 구현 한 Provider 등록
<beans:bean id="customAuthenticationProvider" class="com.company.security.CustomAuthenticationProvider"/> : Provider의 Bean 등록
6. HomeController
package com.company.security; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; /** * Handles requests for the application home page. */ @Controller public class HomeController { @RequestMapping(value = "/login", method = RequestMethod.GET) public String login() {
return "login"; }
@RequestMapping(value = "/loginSuccess", method = RequestMethod.GET) public String loginSuccess(HttpSession session, HttpServletRequest request) {
//CustomAuthenticationProvider에서 set한 값을 로드 User user = (User)SecurityContextHolder.getContext().getAuthentication().getDetails();
//세션 설정 session.setAttribute("id", user.getId()); session.setAttribute("pw", user.getPw()); return "loginSuccess"; }
@RequestMapping(value = "/loginFail", method = RequestMethod.GET) public String loginFail() { return "loginFail"; }
/** * Simply selects the home view to render by returning its name. */ @RequestMapping(value = "/", method = RequestMethod.GET) public String home(HttpServletRequest request) { HttpSession session = request.getSession(); String id =(String)session.getAttribute("id"); String pw =(String)session.getAttribute("pw"); //로그인 후 위 방식으로 Session 값 사용 가능 return "home"; }
}
|
7. View
login.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ page session="false" %> <html> <head> <title>Home</title> </head> <body> <form action="/login.do" method="post"> <div> <label for="id">id:</label> <input type="text" id="id" name="id"/> </div> <div> <label for="password">pw:</label> <input type="password" id="password" name="pw" /> </div> <button type="submit">submit</button> </form> </body> </html> |
로그인 페이지로 security-context.xml에서의 username-parameter, password-parameter 값(id,pw)을 name 태그를 이용하여 설정 후 전달
Action 위치는 security-context.xml에서의 login-processing-url(login.do)로 AuthenticationProvider에 접근하여 인증 절차를 진행
loginSuccess.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ page session="false" %> <html> <head> <title>Home</title> </head> <body> login Success </body> </html> |
loginFail.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ page session="false" %> <html> <head> <title>Home</title> </head> <body> login Fail </body> </html> |
전체흐름
1) web.xml의 Filter 설정에 의해 모든 경로로의 접근은 Spring Security로 우선 접근
2) 인증이 되지않은 사용자는 security-context.xml에서 설정한 login-page(/login)으로 리다이렉션
3) login view의 Form에서 id와 pw를 입력받아 security-context.xml에서 설정한 login-processing-url(/login.do)로 요청
4) login-processiong-url은 컨트롤러 설정이 필요 X, AuthenticationProvider을 구현한 클래스(CustomAuthenticationProvider)의 authenticate로 전달
5) authenticate 함수에서 인증 절차를 진행 한 후 반환 값에 따라 security-context.xml에서 설정한 default-target-url, authentication-failure-url로 이동
Filter > login-page > view > login-processing-url > Provider(인증 절차 진행) > default-target-url(성공 시) , authentication-failure-url(실패 시)
확인
경로 접근 시 /login으로 리다이렉션
fail외의 아이디로 로그인 시 인증 성공
fail로 로그인 시 인증 실패
'Java' 카테고리의 다른 글
[spring] Controller -> JSP 데이터 전달 (0) | 2019.06.28 |
---|---|
[Spring] JUnit 적용하기 (0) | 2018.10.23 |
[Spring] Spring Security 적용 (0) | 2018.10.17 |
[Spring] Error Page 커스터마이징 (0) | 2018.10.15 |
[Spring] 정적 리소스 사용 설정 (0) | 2018.07.28 |