접근 불가 페이지 만들기

금은체리·2023년 11월 16일
0

Spring

목록 보기
20/49

API 접근 권한 제어 이해

🤽 '일반 사용자'는 관리자 페이지에 접속이 인가되지 않아야 함!

1. Spring Security에 대한 "권한(Authority)" 설정방법

  1. 회원 상세정보(UserDetailsImpl)를 통해 "권한(Authority)" 설정 가능
  2. 권한을 1개 이상 설정 가능
  3. "권한 이름" 규칙
  • "ROLE_" 로 시작해야함
    • 예시
      • "ADMIN" 권한 부여 ➡️ "ROLE_ ADMIN"
      • "USER" 권한 부여 ➡️ "ROLE_ USER"
public enum UserRoleEnum {
    USER(Authority.USER),  // 사용자 권한
    ADMIN(Authority.ADMIN);  // 관리자 권한

    private final String authority;

    UserRoleEnum(String authority) {
        this.authority = authority;
    }

    public String getAuthority() {
        return this.authority;
    }

    public static class Authority {
        public static final String USER = "ROLE_USER";
        public static final String ADMIN = "ROLE_ADMIN";
    }
}  
public class UserDetailsImpl implements UserDetails {
		// ...

		@Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        SimpleGrantedAuthority adminAuthority = new SimpleGrantedAuthority("ROLE_ADMIN");
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(adminAuthority);

        return authorities;
    }
}
  • new SimpleGrantedAuthority("ROLE_ADMIN");
    • 예시 코드는 ROLE_ADMIN 으로 고정되어 있지만 아래와 같이 실제 코드에서는 사용자에 저장되어있는 role의 authority값을 사용하여 동적으로 저장됨
UserRoleEnum role = user.getRole();
String authority = role.getAuthority();

SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(authority);
  • UserDetailsImpl 저장된 authorities 값을 사용하여 간편하게 권한 제어 가능

2. Spring Security를 이용한 API 별 권한 제어 방법

  • Controller에 "@Secured" 애너테이션으로 권한 설정 가능

    • @Secured(" 권한 이름 ") 선언

      • 권한 1개 이상 설정 가능
      @Secured(UserRoleEnum.Authority.ADMIN) // 관리자용
      @GetMapping("/products/secured")
      public String getProductsByAdmin(@AuthenticationPrincipal UserDetailsImpl userDetails) {
          System.out.println("userDetails.getUsername() = " + userDetails.getUsername());
          for (GrantedAuthority authority : userDetails.getAuthorities()) {
              System.out.println("authority.getAuthority() = " + authority.getAuthority());
          }  
      
          return "redirect:/";
      }
  • "@Secured" 애너테이션 활성화 방법

@Configuration
@EnableWebSecurity // 스프링 Security 지원을 가능하게 함
@EnableGlobalMethodSecurity(securedEnabled = true) // @Secured 애너테이션 활성화
public class WebSecurityConfig {

접근 불가 페이지 적용

스프링 시큐리티 설정을 이용해 일반 사용자가 '관리자용 상품조회 API에 접속 시도 시 접속 불가 페이지가 뜨도록 구현해보자!

  1. 프론트엔드 개발자 작업 ➡️ Forbidden 페이지 적용

  2. WebSecurityConfig 파일 수정

    • "접근 불가" 페이지 URL 설정 ➡️ "/forbidden.html"
    package com.sparta.springauth.config;
    
    import com.sparta.springauth.jwt.JwtAuthorizationFilter;
    import com.sparta.springauth.jwt.JwtAuthenticationFilter;
    import com.sparta.springauth.jwt.JwtUtil;
    import com.sparta.springauth.security.UserDetailsServiceImpl;
    import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
    import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.http.SessionCreationPolicy;
    import org.springframework.security.web.SecurityFilterChain;
    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
    
    @Configuration
    @EnableWebSecurity // Spring Security 지원을 가능하게 함
    @EnableGlobalMethodSecurity(securedEnabled = true)
    public class WebSecurityConfig {
    
        private final JwtUtil jwtUtil;
        private final UserDetailsServiceImpl userDetailsService;
        private final AuthenticationConfiguration authenticationConfiguration;
    
        public WebSecurityConfig(JwtUtil jwtUtil, UserDetailsServiceImpl userDetailsService, AuthenticationConfiguration authenticationConfiguration) {
            this.jwtUtil = jwtUtil;
            this.userDetailsService = userDetailsService;
            this.authenticationConfiguration = authenticationConfiguration;
        }
    
        @Bean
        public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
            return configuration.getAuthenticationManager();
        }
    
        @Bean
        public JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {
            JwtAuthenticationFilter filter = new JwtAuthenticationFilter(jwtUtil);
            filter.setAuthenticationManager(authenticationManager(authenticationConfiguration));
            return filter;
        }
    
        @Bean
        public JwtAuthorizationFilter jwtAuthorizationFilter() {
            return new JwtAuthorizationFilter(jwtUtil, userDetailsService);
        }
    
        @Bean
        public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
            // CSRF 설정
            http.csrf((csrf) -> csrf.disable());
    
            // 기본 설정인 Session 방식은 사용하지 않고 JWT 방식을 사용하기 위한 설정
            http.sessionManagement((sessionManagement) ->
                    sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            );
    
            http.authorizeHttpRequests((authorizeHttpRequests) ->
                    authorizeHttpRequests
                            .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll() // resources 접근 허용 설정
                            .requestMatchers("/api/user/**").permitAll() // '/api/user/'로 시작하는 요청 모두 접근 허가
                            .anyRequest().authenticated() // 그 외 모든 요청 인증처리
            );
    
            http.formLogin((formLogin) ->
                    formLogin
                            .loginPage("/api/user/login-page").permitAll()
            );
    
            // 필터 관리
            http.addFilterBefore(jwtAuthorizationFilter(), JwtAuthenticationFilter.class);
            http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    
            // 접근 불가 페이지
            http.exceptionHandling((exceptionHandling) ->
                    exceptionHandling
                            // "접근 불가" 페이지 URL 설정
                            .accessDeniedPage("/forbidden.html")
            );
    
            return http.build();
        }
    }
profile
전 체리 알러지가 있어요!

0개의 댓글