본문 바로가기
Spring MVC

[Spring MVC] security 관련

by SUN5066 2020. 9. 28.
반응형
package com.biz.book.auth;

import com.biz.book.mapper.AuthorityDao;
import com.biz.book.mapper.UserDao;
import com.biz.book.model.UserDetailsVO;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

/**
 * spring security 프로젝트에서
 * 사용자 인가와 권한을 관리하는 클래스
 * UserDetailService 를 customizing
 *
 * Customizing
 * 패키지형 솔루션을 가지고 있는 it 회사에서
 * 어떤 회사에 솔루션을 판매하면서
 * 회사의 실정, 업무환경, 여러가지 여건들을 요구분석하여
 * 솔루션을 사용하는 회사에 최적화하는 것
 * */
@RequiredArgsConstructor
@Service("userDetailServiceV1")
public class UserDetailServiceImplV1 implements UserDetailsService {

    /**
     * @Autowired 를 사용하여 객체를 주입받아서 사용해 왔는데
     * @Autowired 로 주입받은 객체에 메로리 누수현상이 발생을 하더라
     *
     * 주입받을 객체를 final 로 선언을 해주는데
     * final 로 선언한 객체는 반드시 생성자에서 객체 초기화(주입)을 해야한다
     * 1. 주입받을 객체를 final 로 선언하고
     * 2. 생성자의 매개변수를 통하여 객체를 초기화한다.
     * 3. 주입받을 객체의 갯수가 늘거나 줄면 생성자를 또 다시 변경 해야하는 번거로움이 있다.
     * 4. lombok 의 @RequiredArgsConstructor 를 사용하면 final 로 선언된
     * 모든 필드변수들을 모아서 생성자로 만들어준다.
     * */
    private final UserDao userDao;
    private final AuthorityDao authDao;
    /**
     * 이 프로젝트에서 사용할 member(user) 관련 table 에서 username 으로
     * 사용자 정보를 SELECT 하고 사용자의 ROLL 정보를 기준으로 사용자의 권한을 설정하여
     * 기능을 수행을 제한하는 설정을 하고
     * 사용자의 여러 세부 정보를 vo 객체에 담아주는 역할 수행
     * */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserDetailsVO userDetailsVO = userDao.findById(username);

        userDetailsVO = UserDetailsVO.builder()
                .username(username)
                .password("12341234")
                .isEnabled(true)
                .build();
        if (userDetailsVO == null) {
            throw new UsernameNotFoundException(username + "정보를 찾을 수 없음!");
        }
        return userDetailsVO;
    }
}
<?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:context="http://www.springframework.org/schema/context"
       xmlns:security="http://www.springframework.org/schema/security"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-4.3.xsd
      http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-4.3.xsd
      http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security-5.2.xsd
      http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">

    <!--  spring security 에서 사용할 AuthenticationProvider 를 구현한 -->
    <!--  클래스를 bean 등록  -->
    <bean id="authProvider" class="com.biz.book.auth.AuthProviderImpl" />
    <!--  커스터마이징 된 AuthorProvider 를 spring security 에서 사용하도록
      security:authentication-manager 에 등록-->
    <security:authentication-manager>
        <security:authentication-provider ref="authProvider"/>
    </security:authentication-manager>
    <!--  spring security 의 핵심 설정 부분  -->
    <!--  security:http  -->
    <!--  login form 설정  -->
    <!--  login 방법 설정  -->
    <!--  login 이 되었을때 인가, 권한 설정  -->
    <!--  security:intercept 이란  -->
    <!--  login 이 되었을때 URL 패턴에 따라 접근 권한을 세밀하게 부여 할 수 있다.  -->

    <!--  접근할 URL 을 pattern 속성에 지정하고  -->
    <!--  접근할 권한이 있는가를 검사하도록 access 속성에 지정한다.  -->

    <!--  패턴 지정에서 주의할 사항  -->
    <!--  패턴은 URL 의 단계가 깊을 수록 위쪽에 먼저 작성을 해주어야 한다.  -->
    <!--  만약 /member/**, /user/a/b/c 순서로 패턴이 있을경우 /member/a/b/c 는 무시된다.  -->
    <!--  이때는 /member/a/b/c, /member/** 순서로 나열해야 한다.  -->

    <security:http auto-config="true" use-expressions="true">
        <security:form-login login-page="/login" username-parameter="username" password-parameter="password"/>
        <security:logout logout-url="/logout"/>

        <!--
        로그인 하는 사용자가
        hasRole 이 true 인 경우에만
        /admin/** 으로 접속
          -->
        <security:intercept-url pattern="/admin/**" access="hasRole('ADMIN')"/>

        <!--    여러 Role 을 지정할땐 hasAnyRole(배열) 사용    -->
        <!--    admin, user 둘다 권한    -->
        <security:intercept-url pattern="/member/mypage" access="hasAnyRole('ADMIN', 'USER')"/>
        <security:intercept-url pattern="/member/password" access="hasAnyRole('ADMIN', 'USER')"/>

        <!--
             위 mypage, password 페이지를 제외한
             모든 /member/** 경로는 permitAll()

             만약 /member/** 얘가 먼저인 경우 밑에
                /member/mypage
                /member/password
                이 둘은 무시됨

                그래서 security:intercept-url 은 작성할때 순서정하는게 중요함
             -->
        <security:intercept-url pattern="/member/**" access="permitAll()"/>
        <security:intercept-url pattern="/books/**" access="hasAnyRole('ADMIN', 'USER')"/>

        <!--        -->
        <security:intercept-url pattern="/**" access="permitAll()"/>

    </security:http>
</beans>

반응형

댓글