Notice
Recent Posts
Recent Comments
Link
관리 메뉴

look-forest

기타 : 메소드 시큐리티, 연동(웹 MVC, 타임리프, 스프링 데이터 JPA) 본문

Spring/Spring Security (feat. JWT, OAuth2)

기타 : 메소드 시큐리티, 연동(웹 MVC, 타임리프, 스프링 데이터 JPA)

studyHub 2024. 11. 10. 20:48

메소드 시큐리티

서비스 계층 메소드를 직접 호출 시 사용하는 보안 기능. (웹 기반일 경우 필요 X)

 

1. 메소드 시큐리티 설정

@EnableMethodSecurity 애노테이션을 통해 메서드 보안이 활성화되며, 

AOP 를 통해 @PreAuthorize, @PostAuthorize 같은 메서드 보안 애노테이션을 사용할 수 있게 된다

@EnableMethodSecurity(securedEnabled = true, prePostEnabled = true, jsr250Enabled = true)
@Configuration
public class MethodSecurity {
    // 추가적인 보안 설정이 필요한 경우 이곳에 작성

    // AuthenticationManager를 Bean으로 등록
    @Bean
    AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    @Bean
    public RoleHierarchy roleHierarchy() {
        return RoleHierarchyImpl.fromHierarchy("ROLE_ADMIN > ROLE_USER");
    }
}

 

 

2. 메소드 보안 적용할 메소드에 애노테이션 추가

@Service
public class SampleService {

    @Secured("ROLE_USER") //메소드 호출 전 권한 검사
    public void dashboard() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Object principal = authentication.getPrincipal();
        log.info("authentication = {}", authentication);
        log.info("account.getUsername() = {}", ((UserDetails) principal).getUsername());
    }

    @PreAuthorize("hasRole('ADMIN')")
    public void dashboardAdmin() {}
}

 

 

메서드 보안 동작 흐름

 

 

 


연동

Spring Web MVC - Security가 제공하는 Argument Resolver 

@AuthenticationPrincipal을 사용하면 웹 MVC 핸들러 아규먼트로 Principal 객체를 받을 수 있다.

 

1. UserDetailsService 구현체에서 리턴하는 객체를 매개변수로 받을 수 있다

@AuthenticationPrincipal UserAccount userAccount
//UserDetails 타입으로 반환하기 위한 어댑터
public class UserAccount extends User {

    private Account account;

    public UserAccount(Account account) {
        super(account.getUsername(), account.getPassword(), List.of(new SimpleGrantedAuthority("ROLE_" + account.getRole())));
        this.account = account;
    }

    public Account getAccount() {
        return account;
    }
}

 

2. 도메인에서 사용하는 객체로 바로 받아올 경우 아래 옵션 추가

@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : account") Account account

기니까 커스텀 애노테이션 만들어 붙이자

@CurrentUser Account account

 


스프링 데이터 연동

@Query 애노테이션에서 SpEL로 principal 참조할 수 있는 기능

 - spring-security-data 의존성을 추가해야 한다.

UserDetailsService로 반환한 Principal을 사용할 수 있다. (내부 필드도 getter로 접근 가능)

public interface BookRepository extends JpaRepository<Book, Integer> {
    //security 의 기능 사용
    @Query("select b from Book b where b.author.id = ?#{principal.account.id}")
    List<Book> findCurrentUserBooks();
}

 


타임리프 스프링 시큐리티 확장팩

Thymeleaf 템플릿 내에서 Spring Security의 인증, 권한 관련 기능을 쉽게 사용

 - thymeleaf-extras-springsecurity6 라이브러리를 추가해야 한다.

<body>
    <h1 th:text="${message}">Index</h1>
    <div th:if="${#authorization.expr('isAuthenticated()')}">
        <h2 th:text="${#authentication.name}">Name</h2>
        <a href="/logout" th:href="@{/logout}">Logout</a>
    </div>
    <div th:unless="${#authorization.expr('isAuthenticated()')}">
        <a href="/login" th:href="@{/login}">Login</a>
    </div>
</body>

문제는 expr 부분이 전혀 type safe하지 않다는 것이다.

 

sec 네임스페이스를 추가하면 자동 완성 등의 편의 기능을 지원한다.

<html lang="en" xmlns:th="http://www.thymeleaf.org" 
		xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
</head>
<body>
    <h1 th:text="${message}">Index</h1>
    <div sec:authorize-expr="isAuthenticated()">
        <h2 sec:authentication="name">Name</h2>
        <a href="/logout" th:href="@{/logout}">Logout</a>
    </div>
    <div sec:authorize-expr="!isAuthenticated()">
        <a href="/login" th:href="@{/login}">Login</a>
    </div>
</body>

참고 자료 & 이미지 출처
스프링부트 시큐리티 (백기선 님)

 

https://spring.io/projects/spring-security

 

Spring Security

Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications. Spring Security is a framework that focuses on providing both authentication and authoriz

spring.io