Spring 심화반 - 2주차 - 2

귀찮Lee·2022년 4월 14일
0
post-custom-banner

2022년 4월 13일(수)
[스파르타코딩클럽] Spring 심화반 - 2주차 - 2

◎ 회원별 상품 등록 및 조회

  • POST "/api/products" 요청 → HTTP 403 Forbidden-
    -> CSRF protection 때문이다.

    • POST 요청마다 처리
      http.csrf()
            .ignoringAntMatchers("/user/**")
           .ignoringAntMatchers("/api/products/**");
    • CSRF 를 disable (해당 프로젝트에서는 이것으로 진행)
      // CSRF protection 을 비활성화
      http.csrf().disable();
  • product에 저장한 사람의 userId를 저장

    • Product, ProductService 에 UserId 값을 추가
    • ProdutController.js
    @PostMapping("/api/products")
      public Product createProduct(@RequestBody ProductRequestDto requestDto,
                                   @AuthenticationPrincipal UserDetailsImpl userDetails) {
          // 로그인 되어 있는 회원 테이블의 ID
          Long userId = userDetails.getUser().getId();
    
          Product product = productService.createProduct(requestDto, userId);
      return product;
    • ProductRepository.js
    public interface ProductRepository extends JpaRepository<Product, Long> {
          List<Product> findAllByUserId(Long userId);  // 4주차에서 자세히 설명 / userId를 통해 해당 데이터를 찾는다.
     }

◎ 관리자 상품 조회

  • 설계

    • 타임리프를 통해 관리자에게만 아래 코드를 내보내줌
      <div id="admin"></div>
    • 이걸 클라이언트에서 파악해 GET /api/admin/products 요청을 함
  • template를 내보내는 곳에 아래 사항 추가 (HomeController.js)

if (userDetails.getUser().getRole() == UserRoleEnum.ADMIN) {
            model.addAttribute("admin_role", true);
        }
  • "관리자" 용 상품 목록 조회 API 구현 : ProductController.js
// (관리자용) 등록된 모든 상품 목록 조회
    @GetMapping("/api/admin/products")
    public List<Product> getAllProducts() {
        return productService.getAllProducts();
    }
  • "관리자" 용 상품 목록 조회 API 구현 : ProductController.js
// 모든 상품 조회 (관리자용)
    public List<Product> getAllProducts() {
        return productRepository.findAll();
    }

◎ 접근 불가 페이지 만들기

  • 문제점: 일반 회원도 GET /api/admin/products 요청을 할 수 있다.

  • 스프링 시큐리티에 "권한 (Authority)" 설정방법

    1. 회원 상세정보 (UserServiceImpl) 를 통해 "권한 (Authority)" 설정 가능
    2. 권한을 1개 이상 설정 가능
    3. "권한 이름" 규칙
      1. "ROLE_" 로 시작해야 함
        예) "ADMIN" 권한 부여 → "ROLE_ADMIN"
    • UserDetailsImpl.js
    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;
         }
     }
  • 스프링 시큐리티를 이용한 API 별 권한 제어 방법

    • Controller 에 "@Secured" 어노테이션으로 권한 설정 가능
    // (관리자용) 등록된 모든 상품 목록 조회
      @Secured("ROLE_ADMIN")
      @GetMapping("/api/admin/products")
      public List<Product> getAllProducts() {
          return productService.getAllProducts();
      }
    • "@Secured" 어노테이션 활성화 방법
      -> WebSecurityConfig.js 에 @EnableGlobalMethodSecurity(securedEnabled = true)
    @Configuration
    @EnableWebSecurity // 스프링 Security 지원을 가능하게 함
    @EnableGlobalMethodSecurity(securedEnabled = true) // @Secured 어노테이션 활성화
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  • 직접 적용

// security > WebSecurityConfig.js 일부


@Configuration
@EnableWebSecurity // 스프링 Security 지원을 가능하게 함
@EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

...

				.and()
                .exceptionHandling()
                // "접근 불가" 페이지 URL 설정
                .accessDeniedPage("/forbidden.html");
// model > UserRoleEnum
// 코드 수정 용이성을 위해 아래와 같이 함

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";
    }
}
// controller > ProductController.js 일부
// 관리자용 상품조회 API 에 @Secured 어노테이션으로 권한 설정

// (관리자용) 등록된 모든 상품 목록 조회
    @Secured(value = UserRoleEnum.Authority.ADMIN)
    @GetMapping("/api/admin/products")
    public List<Product> getAllProducts() {
        return productService.getAllProducts();
    }
// security > UserDetailsImpl.js 일부
// 스프링 시큐리티가 로그인한 회원의 권한을 인식하도록 수정
	private final User user;

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

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

        return authorities;
    }
profile
배운 것은 기록하자! / 오류 지적은 언제나 환영!
post-custom-banner

0개의 댓글