1. 소개

이 예제에서는 스프링 Security 표현식과 이러한 표현식을 사용하는 실제 예제에 중점을 둘 것입니다.

ACL과 같은 보다 복잡한 구현을 살펴보기 전에 Security 표현을 제대로 이해하는 것이 중요합니다. 올바르게 사용하면 매우 유연하고 강력할 수 있기 때문입니다.

2. 메이븐 의존성

Spring Security를 ​​사용하려면 pom.xml 파일 에 다음 섹션을 포함해야 합니다.

<dependencies>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
        <version>5.6.0</version>
   </dependency>
</dependencies>

최신 버전은 여기 에서 찾을 수 있습니다 .

이 의존성은 Spring Security에만 적용됩니다. 완전한 웹 애플리케이션을 위해 s pring-corespring-context 를 추가해야 합니다.

3. 구성

먼저 Java 구성을 살펴보겠습니다.

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@ComponentScan("com.baeldung.security")
public class SecurityJavaConfig {
    ...
}

물론 XML 구성도 수행할 수 있습니다.

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans ...>
    <global-method-security pre-post-annotations="enabled"/>
</beans:beans>

4. 웹 Security 표현

이제 Security 표현을 살펴보겠습니다.

  • hasRole , hasAnyRole
  • hasAuthority , hasAnyAuthority
  • 모두 허용 , 모두 거부
  • isAnonymous , isRememberMe , isAuthenticated , isFullyAuthenticated
  • 교장 , 인증
  • hasPermission

4.1. hasRole, hasAnyRole

이러한 식은 애플리케이션의 특정 URL 및 메서드에 대한 액세스 제어 또는 권한 부여를 정의하는 역할을 합니다.

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    ...
    .antMatchers("/auth/admin/*").hasRole("ADMIN")
    .antMatchers("/auth/*").hasAnyRole("ADMIN","USER")
    ...
}

위의 예에서는 /auth/로 시작하는 모든 링크에 대한 액세스를 지정하여 USER 또는 ADMIN 역할로 로그인하는 사용자로 제한했습니다 . 또한 /auth/admin/ 으로 시작하는 링크에 액세스하려면 시스템에서 ADMIN 역할이 있어야 합니다 .

다음과 같이 작성하여 XML 파일에서 동일한 구성을 얻을 수 있습니다.

<http>
    <intercept-url pattern="/auth/admin/*" access="hasRole('ADMIN')"/>
    <intercept-url pattern="/auth/*" access="hasAnyRole('ADMIN','USER')"/>
</http>

4.2. hasAuthority, hasAny권한

역할과 권한은 Spring에서 유사합니다.

주요 차이점은 역할에 특별한 의미 체계가 있다는 것입니다. Spring Security 4부터 ' ROLE_ ' 접두어는 역할 관련 방법에 의해 자동으로 추가됩니다(아직 없는 경우).

따라서 hasAuthority('ROLE_ADMIN') 는 ' ROLE_ ' 접두사가 자동으로 추가 되기 때문에 hasRole('ADMIN') 과 유사합니다 .

권한 사용의 이점은 ROLE_ 접두사를 전혀 사용할 필요가 없다는 것 입니다.

다음은 특정 권한을 가진 사용자를 정의하는 간단한 예입니다.

@Bean
public InMemoryUserDetailsManager userDetailsService() {
    UserDetails admin = User.withUsername("admin")
        .password(encoder().encode("adminPass"))
        .roles("ADMIN")
        .build();
    UserDetails user = User.withUsername("user")
        .password(encoder().encode("userPass"))
        .roles("USER")
        .build();
    return new InMemoryUserDetailsManager(admin, user);
}

그런 다음 다음 권한 표현을 사용할 수 있습니다.

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    ...
    .antMatchers("/auth/admin/*").hasAuthority("ADMIN")
    .antMatchers("/auth/*").hasAnyAuthority("ADMIN", "USER")
    ...
}

보시다시피 여기에서는 역할에 대해 전혀 언급하지 않습니다.

또한 Spring 5부터 PasswordEncoder  빈이 필요합니다.

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

마지막으로 XML 구성을 사용하여 동일한 기능을 달성할 수 있는 옵션도 있습니다.

<authentication-manager>
    <authentication-provider>
        <user-service>
            <user name="user1" password="user1Pass" authorities="ROLE_USER"/>
            <user name="admin" password="adminPass" authorities="ROLE_ADMIN"/>
        </user-service>
    </authentication-provider>
</authentication-manager>
<bean name="passwordEncoder" 
  class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>

그리고:

<http>
    <intercept-url pattern="/auth/admin/*" access="hasAuthority('ADMIN')"/>
    <intercept-url pattern="/auth/*" access="hasAnyAuthority('ADMIN','USER')"/>
</http>

4.3. 모두 허용, 모두 거부

이 두 어노테이션도 매우 간단합니다. 당사는 당사 서비스의 일부 URL에 대한 액세스를 허용하거나 거부할 수 있습니다.

예를 살펴보겠습니다.

...
.antMatchers("/*").permitAll()
...

이 구성을 사용하면 모든 사용자(익명 사용자와 로그인 사용자 모두)가 '/'로 시작하는 페이지(예: 홈페이지)에 액세스할 수 있는 권한을 부여합니다.

전체 URL 공간에 대한 액세스를 거부할 수도 있습니다.

...
.antMatchers("/*").denyAll()
...

그리고 다시 XML을 사용하여 동일한 구성을 수행할 수 있습니다.

<http auto-config="true" use-expressions="true">
    <intercept-url access="permitAll" pattern="/*" /> <!-- Choose only one -->
    <intercept-url access="denyAll" pattern="/*" /> <!-- Choose only one -->
</http>

4.4. isAnonymous, isRememberMe, isAuthenticated, isFullyAuthenticated

이 하위 섹션에서는 사용자의 로그인 상태와 관련된 표현에 중점을 둘 것입니다. 우리 페이지에 로그인하지 않은 사용자부터 시작하겠습니다. Java 구성에서 다음을 지정하면 승인되지 않은 모든 사용자가 기본 페이지에 액세스할 수 있습니다.

...
.antMatchers("/*").anonymous()
...

다음은 XML 구성에서 동일합니다.

<http>
    <intercept-url pattern="/*" access="isAnonymous()"/>
</http>

웹사이트를 사용하는 모든 사람이 로그인해야 하도록 웹사이트를 보호하려면 isAuthenticated() 메서드를 사용해야 합니다.

...
.antMatchers("/*").authenticated()
...

또는 XML 버전을 사용할 수 있습니다.

<http>
    <intercept-url pattern="/*" access="isAuthenticated()"/>
</http>

또한 isRememberMe()isFullyAuthenticated() 라는 두 가지 추가 표현식이 있습니다. 쿠키 사용을 통해 Spring은 기억하기 기능을 활성화하므로 매번 시스템에 로그인할 필요가 없습니다. Remember Me 에 대한 자세한 내용은 여기에서 확인할 수 있습니다 .

Remember me 기능으로 로그인한 사용자에게 액세스 권한을 부여하려면 다음을 사용할 수 있습니다.

...
.antMatchers("/*").rememberMe()
...

XML 버전을 사용할 수도 있습니다.

<http>
    <intercept-url pattern="*" access="isRememberMe()"/>
</http>

마지막으로, 당사 서비스의 일부에서는 사용자가 이미 로그인한 경우에도 사용자를 다시 인증해야 합니다. 예를 들어 사용자가 설정이나 결제 정보를 변경하려고 한다고 가정해 보겠습니다. 시스템의 보다 민감한 영역에서 수동 인증을 요청하는 것이 좋습니다.

이를 위해 isFullyAuthenticated() 를 지정할 수 있습니다. 이는 사용자가 익명 또는 기억 사용자가 아닌 경우 true 를 반환 합니다.

...
.antMatchers("/*").fullyAuthenticated()
...

XML 버전은 다음과 같습니다.

<http>
    <intercept-url pattern="*" access="isFullyAuthenticated()"/>
</http>

4.5. 주체, 인증

이러한 표현식을 통해 현재 인증된(또는 익명의) 사용자를 나타내는 주체 개체와 SecurityContext 의 현재 인증 개체 에 각각 액세스할 수 있습니다.

예를 들어 principal 을 사용 하여 로그인한 사용자가 액세스할 수 있는 사용자의 이메일, 아바타 또는 기타 데이터를 로드할 수 있습니다.

그리고 인증 은 부여된 권한과 함께 전체 인증 개체 에 대한 정보를 제공합니다 .

이 두 표현식은 모두 Retrieve User Information in Spring Security 문서에 자세히 설명되어 있습니다.

4.6. hasPermission API

이 표현은 문서화 되어 있으며 표현 시스템과 Spring Security의 ACL 시스템 사이의 브리지 역할을 하여 추상 권한을 기반으로 개별 도메인 개체에 대한 권한 부여 제약 조건을 지정할 수 있습니다.

예를 들어 보겠습니다. 저자가 제안한 기사를 출판해야 하는지를 결정하는 주 편집자와 협력하여 기사 작성을 허용하는 서비스가 있다고 상상해 보십시오.

이러한 서비스의 사용을 허용하기 위해 액세스 제어 방법으로 다음 방법을 만들 수 있습니다.

@PreAuthorize("hasPermission(#articleId, 'isEditor')")
public void acceptArticle(Article article) {
}

인증된 사용자만 이 메서드를 호출할 수 있으며 서비스에서 isEditor 권한이 있어야 합니다.

또한 애플리케이션 컨텍스트에서 PermissionEvaluator 를 명시적으로 구성해야 한다는 점을 기억해야 합니다 . 여기서 customInterfaceImplementation 은 PermissionEvaluator 를 구현하는 클래스가 됩니다 .

<global-method-security pre-post-annotations="enabled">
    <expression-handler ref="expressionHandler"/>
</global-method-security>

<bean id="expressionHandler"
    class="org.springframework.security.access.expression
      .method.DefaultMethodSecurityExpressionHandler">
    <property name="permissionEvaluator" ref="customInterfaceImplementation"/>
</bean>

물론 Java 구성으로도 이 작업을 수행할 수 있습니다.

@Override
protected MethodSecurityExpressionHandler expressionHandler() {
    DefaultMethodSecurityExpressionHandler expressionHandler = 
      new DefaultMethodSecurityExpressionHandler();
    expressionHandler.setPermissionEvaluator(new CustomInterfaceImplementation());
    return expressionHandler;
}

5. 결론

이 기사는 Spring Security Expressions에 대한 포괄적인 소개 및 사용방법(예제)입니다.

여기에서 설명하는 모든 예제 는 GitHub 프로젝트에서 사용할 수 있습니다 .

Security footer banner