Skip to content

Comments

[김유민] sprint9#312

Open
kimyumin03 wants to merge 18 commits intocodeit-bootcamp-spring:김유민from
kimyumin03:김유민-sprint9

Hidden character warning

The head ref may contain hidden characters: "\uae40\uc720\ubbfc-sprint9"
Open

[김유민] sprint9#312
kimyumin03 wants to merge 18 commits intocodeit-bootcamp-spring:김유민from
kimyumin03:김유민-sprint9

Conversation

@kimyumin03
Copy link
Collaborator

@kimyumin03 kimyumin03 commented Nov 23, 2025

요구사항

기본

Spring Security 환경설정

  • Spring Security 의존성 추가
  • com.sprint.mission.discodeit.config 패키지에 SecurityConfig 클래스 생성
  • SecurityFilterChain Bean 선언
  • 기본 SecurityFilterChain 등록 후 필터 목록 디버깅 (PR에 첨부)
  • 개발 환경에서 Spring Security 로깅 레벨을 trace로 설정

having filters [DisableEncodeUrl, WebAsyncManagerIntegration, SecurityContextHolder, HeaderWriter,
Csrf, Logout, UsernamePasswordAuthentication, DefaultResources, DefaultLoginPageGenerating,
DefaultLogoutPageGenerating, BasicAuthentication, RequestCacheAware,
SecurityContextHolderAwareRequest, AnonymousAuthentication, ExceptionTranslation, Authorization]

CSRF 보호 설정하기

image
  • CsrfTokenRepository 구현체를 CookieCsrfTokenRepository로 설정
  • CsrfTokenRequestHandler 컴포넌트를 대체
  • CSRF 토큰을 발급하는 API를 구현
    • GET /api/auth/csrf-token
    • 응답: 203 Void
  • CsrfToken 파라미터 주입 및 토큰 초기화 확인

회원가입

  • API 스펙
    엔드포인트: POST /api/users
    요청: Body UserCreateRequest, MultipartFile
    응답: 200 UserDto
  • 회원가입 시 비밀번호는 PasswordEncoder를 통해 해시로 저장
  • PasswordEncoder의 구현체는 BCryptPasswordEncoder를 활용

인증 - 로그인

  • formLogin을 기본값으로 활성화하고, 추가된 필터를 확인
  • Spring Security의 formLogin 인증 흐름은 그대로 유지하면서 필요한 부분만 대체
image
  • 로그인을 처리할 url을 /api/auth/login로 설정
  • UserDetailsService 컴포넌트를 대체
  • UserDetails 컴포넌트를 대체
  • AuthenticationSuccessHandler 컴포넌트를 대체
  • 로그인 처리는 SecurityFilterChain에서 모두 처리되기 때문에 기존에 구현했던 로그인 관련 코드는 제거

인증 - 세션을 활용한 현재 사용자 정보 조회

  • 세션ID를 통해 사용자의 기본 정보(UserDto)를 가져올 수 있도록 API를 정의
  • API 스펙
    - 엔드포인트: GET /api/auth/me
    - 요청: Header(자동 포함) Cookie: JSESSIONID=…
    - 응답: 200 UserDto
    - @AuthenticationPrincipal 활용

인증 - 로그아웃

  • Spring Security의 logout 흐름은 그대로 유지하면서 필요한 부분만 대체

  • 로그아웃을 처리할 url을 /api/auth/logout로 설정
    http
    .logout(logout -> logout
    .logoutUrl(...)
    )

  • LogoutSuccessHandler 컴포넌트를 대체
    http
    .logout(logout -> logout
    ...
    .logoutSuccessHandler(...)
    )

인가 - 권한 정의

image
- 관리자: ADMIN
- 채널 매니저: CHANNEL_MANAGER
- 일반 사용자: USER
  • DB 스키마 변경
    CREATE TABLE users
    (
    ...
    role varchar(20) NOT NULL
    );

ALTER TABLE users
ADD role varchar(20) NOT NULL;

  • 회원가입 시 기본 권한: USER

  • 사용자 권한을 수정하는 API를 구현

  • API 스펙
    - 엔드포인트: PUT /api/auth/role
    - 요청: Body UserRoleUpdateRequest
    - 응답: 200 UserDto

  • 애플리케이션 실행 시 ADMIN 권한을 가진 어드민 계정이 초기화되도록 구현하세요.

  • 어드민 계정이 없는 경우에만 초기화

  • DiscodeitUserDetails.getAuthorities 수정

인가 - 권한 적용

  • authorizeHttpRequests를 활성화하고, 모든 요청을 인증하도록 설정
    http
    .authorizeHttpRequests(auth -> auth
    .anyRequest().authenticated()
    )

  • 다음의 요청은 인증하지 않도록 설정
    http
    .authorizeHttpRequests(auth -> auth
    ...
    .requestMatchers(...).permitAll()
    )

  • Method Security를 활성화
    ...
    @EnableMethodSecurity
    public class SecurityConfig {...}

  • Service의 메소드 별로 아래의 조건에 맞게 권한을 수정

    • 퍼블릭 채널 생성, 수정, 삭제는 CHANNEL_MANAGER 권한을 가져야합니다.
    • 사용자 권한 수정은 ADMIN 권한을 가져야합니다

구현 위치 요약

  • Spring Security 기본 설정

    • SecurityConfig
      • SecurityFilterChain Bean 등록
      • csrf + CookieCsrfTokenRepository.withHttpOnlyFalse() 설정
      • SpaCsrfTokenRequestHandler 적용
      • formLogin().loginProcessingUrl("/api/auth/login")
      • logout().logoutUrl("/api/auth/logout")
      • authorizeHttpRequests + permitAll 대상 설정
      • @EnableMethodSecurity
      • PasswordEncoder(BCrypt) Bean 등록
      • RoleHierarchyMethodSecurityExpressionHandler Bean 등록
  • CSRF 토큰 발급 / 세션 기반 사용자 조회 / 권한 변경 API

    • AuthApi, AuthController
      • GET /api/auth/csrf-token (203, CSRF 토큰 발급)
      • GET /api/auth/me (세션 기반 현재 사용자 조회, @AuthenticationPrincipal)
      • PUT /api/auth/role (사용자 권한 수정)
  • 인증 관련 컴포넌트

    • DiscodeitUserDetailsService (UserDetailsService 구현)
    • DiscodeitUserDetails (UserDto + 비밀번호 보관, getAuthorities에서 ROLE_... 반환)
    • LoginSuccessHandler (로그인 성공 시 UserDto 응답)
    • LoginFailureHandler (로그인 실패 시 에러 응답)
    • HttpStatusReturningLogoutSuccessHandler (로그아웃 시 204 응답)
  • 회원가입 / 비밀번호 해시 / 권한 기본값

    • User 엔티티
      • role 필드 추가 (Role enum: ADMIN, CHANNEL_MANAGER, USER)
      • 생성자에서 기본 권한 Role.USER 설정
    • UserDto, UserMapper (역할 포함 매핑)
    • BasicUserService#create (회원가입 시 PasswordEncoder로 비밀번호 해시)
    • BasicUserService#update (비밀번호 변경 시 재해시)
    • BasicUserService#updateRole (권한 변경, @PreAuthorize("hasRole('ADMIN')"))
  • 채널 인가 적용

    • BasicChannelService
      • 퍼블릭 채널 create / update / delete
        @PreAuthorize("hasRole('CHANNEL_MANAGER')") 적용
  • DB 스키마 변경

    • schema.sql
      • users 테이블에 role varchar(20) NOT NULL 컬럼 추가

멘토에게

  • 셀프 코드 리뷰를 통해 질문 이어가겠습니다.

@kimyumin03 kimyumin03 requested a review from azjaehyun November 25, 2025 00:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant