[Spring] 접근 불가 페이지

thingzoo·2023년 6월 30일
0

Spring

목록 보기
41/54
post-thumbnail
post-custom-banner

API 접근 권한 제어 이해

'일반 사용자'는 관리자 페이지에 접속이 인가되지 않아야 한다.

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

  • 회원 상세정보 (UserDetailsImpl) 를 통해 "권한 (Authority)" 1개 이상 설정 가능
  • "권한 이름" 규칙
    • "ROLE_" 로 시작해야 함
      • "ADMIN" 권한 부여 → "ROLE_ADMIN"
      • "USER" 권한 부여 → "ROLE_USER"
public class UserDetailsImpl implements UserDetails {
		// ...

		@Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            UserRoleEnum role = user.getRole();
            String authority = role.getAuthority();

            SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(authority);
            Collection<GrantedAuthority> authorities = new ArrayList<>();
            authorities.add(simpleGrantedAuthority);

            return authorities;
        }
}
  • new SimpleGrantedAuthority(authority);
    • 사용자에 저장되어있는 role의 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 {

접근 불가 페이지 적용

  • WebSecurityConfig 파일 수정
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true) // @Secured 애너테이션 활성화
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
공부한 내용은 바로바로 기록하자!
post-custom-banner

0개의 댓글