반응형

[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

+ Recent posts