[Spring Security/Thymeleaf] 로그인 기능 구현 (4) Role 설정
본문 바로가기

Web 개발/게시판 만들기

[Spring Security/Thymeleaf] 로그인 기능 구현 (4) Role 설정

728x90
반응형

💡 이전 내용

Spring의 하위 프레임워크로 애플리케이션의 보안을 담당하며, 인증과 인가에 중점을 두고 있습니다.

지난 글에서는 인증의 대표적인 예시로 로그인 기능을 구현하였습니다.

이번 글에서는 인가의 대표적인 예시로 역할 및 권한 기능을 구현하겠습니다.

 

📖 개념 정리

1. 인가란?

엔터프라이즈 애플리케이션의 경우, 모든 사용자가 전체 애플리케이션에 접근할 수 있는 것은 아닙니다.

Spring Security를 사용하면 역할과 권한을 기반으로 사용자의 접근을 제어할 수 있습니다.

 

2. 역할(Role)이란?

특정 수준의 권한 부여를 나타내며, 하나의 역할은 여러 권한을 가질 수 있습니다.

관리자, 사용자, 영업사원, 고객센터 등이 있습니다.

 

3. 권한(Authority, Operation)이란?

보다 세분화된 방식으로 접근을 제한하는 방식입니다.

READ, WRITE, EDIT, DELETE, ACCESS, ASSIGN, SHARE, APPEND 등이 있습니다.

 

4. Role 과 Authority 의 차이(예시)

예를 들어, A계정과 B계정은 둘다 관리자로서 ADMIN 역할을 가지고 있지만,

A계정은 게시글을 등록할 수만 있으며, B계정은 게시글을 삭제할 수만 있다고 했을 때

A계정과 B계정은 역할은 같지만 권한은 다르게 부여해야합니다.

 

💻 Role 설정 기능 구현

이 글에서는 Role 기반의 접근 제어를 다루고 있으며, 세부적인 권한에 대해서는 다루지 않겠습니다.

또한 모든 사용자에게 User 역할을 부여하고, 추후 관리자 페이지에 역할 및 권한 부여 기능을 추가하겠습니다.

 

1. Role 생성

public enum UserRole {
    ADMIN("관리자"),
    MANAGER("매니저"),
    USER("일반사용자");

    private String label;

    private UserRole(String label) {
        this.label = label;
    }

    public String getLabel() {
        return this.label;
    }
}

 

2. 사용자에게 Role 부여

Accout 생성 시 Role 을 User 로 초기화하여, 모든 사용자에게 User 역할을 부여하였습니다.

다른 Role에 대한 접근 확인 시, DB에서 값을 변경하여 테스트 하겠습니다.

@Getter
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Account implements Serializable {

    ...

    @Enumerated(EnumType.STRING)
    private UserRole userRole = UserRole.USER;
    
}

 

3. Role 가져오기

Spring Security에서 접근 제어는 UserDetails 의 getAuthorities() 를 이용하여 구현할 수 있습니다.

Role 부여와 Authority 부여는 기본적으로 동일한 방식이지만, Role 부여할 때는 반드시 prefix로 'ROLE_' 을 써줘야 합니다.

public class CustomUserDetails implements UserDetails {

    private Account account;

    public CustomUserDetails(Account account) {
        this.account = account;
    }

    @Override
    public List<GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority("ROLE_" + account.getUserRole().name()));
        return authorities;
    }
    
    ...
}

 

4. 요청(Request)시 접근 제어 설정

/admin/ 이 포함된 URL 에 접근할 수 있는 권한은 ADMIN,

/manager/ 이 포함된 URL 에 접근할 수 있는 권한은 ADMIN과 MANAGER 로 설정하였습니다.

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
    
        ...
    
        // 접근 권한
        http.authorizeRequests()
                .mvcMatchers("/", "/login", "/signup").permitAll()
                .mvcMatchers("/admin/**").hasRole(UserRole.ADMIN.name())
                .mvcMatchers("/manager/**").hasAnyRole(UserRole.ADMIN.name(), UserRole.MANAGER.name())
                .anyRequest().authenticated();
    }
}

 

5. URL 접근

"/admin/list"는 관리자 역할을 가진 사용자만 접근할 수 있으며, 접근 시 "관리자" 라는 텍스트가 보여집니다.

@Slf4j
@Controller
@AllArgsConstructor
public class AccountController {

    @GetMapping("/")
    public String index() {
        return "index";
    }

    @ResponseBody
    @GetMapping("/admin/list")
    public String adminPage() {
        return "관리자";
    }

    @ResponseBody
    @GetMapping("/manager/list")
    public String managerPage() {
        return "매니저";
    }

}

 

6. 화면에 사용자 정보 출력

"/"는 모든 사용자가 접근할 수 있습니다.

로그인하지 않은 사용자는 "로그인" 버튼만 보여지며, 로그인한 사용자에게는 아이디와 "로그아웃" 버튼이 보여집니다.

로그인한 사용자는 역할에 따라 추가 문구가 다르게 보입니다.

<!DOCTYPE html>
<html lang="en"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{board2/layouts/default_layout}">

<div layout:fragment="content">

    <h1>스프링 시큐리티 데모</h1>
    <div sec:authorize="isAuthenticated()">
        <p>
            안녕하세요,
            <span sec:authentication="principal.username"></span> 님
            <span sec:authentication="principal.authorities"></span>
        </p>

        <div sec:authorize="hasRole('USER')">
            <span>사용자에게 보이는 문구</span>
        </div>
        <div sec:authorize="hasRole('MANAGER')">
            <span>매니저에게 보이는 문구</span>
        </div>
        <div sec:authorize="hasRole('ADMIN')">
            <span>관리자에게 보이는 문구</span>
        </div>

        <a th:href="@{/logout}">로그아웃</a>
    </div>
    
    <div sec:authorize="isAnonymous()">
        <a th:href="@{/login}">로그인</a>
    </div>
</div>

</html>

 

💬 실행 화면

 

 

 

 

참고 사이트:

https://jiurinie.tistory.com/71

https://www.javadevjournal.com/spring-security/spring-security-roles-and-permissions/

https://dev-gorany.tistory.com/139

 

 

728x90
반응형