스프링부트 - 스프링 시큐리티

2025. 5. 11. 21:36·Spring
728x90
반응형
SMALL

스프링 시큐리티란?

웹 애플리케이션에 인증과 권한 기능을 쉽게 적용할 수 있도록 도와주는 프레임워크이다.

로그인, 로그아웃, 비밀번호 암호화, 권한별 페이지 제한, 자동 로그인, CSRF공격 방어 등에 유용하게 사용된다.

@Configuration

@SecurityFilterChain

@UserDetailService

등을 활용해서 설정하고 구현된다.

 

인증(Authentication) 과 인가(Authorization)

보통 인증 절차를 거친 후 인가 절차를 진행한다.

  • 인증: 해당 사용자가 본인이 맞는지 확인하는 절차
  • 인가: 인증된 사용자가 요청된 자원에 접근가능한가를 결정하는 절차

일단 스프링에서 스프링 시큐리티를 사용하려면 Maven이나 Gradle에 

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

해당 의존성을 주입시켜줘야한다.

 

package com.example.security.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello() {
        return "안녕하세요!";
    }
}

시큐리티 의존성을 주입하고 /hello경로로 접근해보자

hello경로로 접근 시 자동으로 기본 로그인 페이지로 리디렉션 된다.

스프링 시큐리티는 기본으로 아이디와 비밀번호가 콘솔에 출력이 되는데

아이디는 user로 설정하고 기본비밀번호는 콘솔에 해당 이름으로 출력이 된다.

스프링 시큐리티 직접설정하는 방법

@Configuration
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/admin").authenticated()
                        .anyRequest().permitAll())
               .formLogin(form -> form
                        .defaultSuccessUrl("/hello", true)
                        .permitAll())
                .logout(logout -> logout
                        .logoutSuccessUrl("/hello"));
        return http.build();
    }
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

SecurityConfig.java파일의 filterChain을 빈으로 등록하여준다.

비밀번호 암호화를 위해서 passwordEncoder메서드를 빈으로 등록해준다.

.requestMatchers("/admin").authenticated()

로그인 한 사람만 접근가능한 부분이다.

.anyRequest().permitAll())

나머지 경로는 모두 허용이 된다.

.formLogin(form -> form
                        .defaultSuccessUrl("/hello", true)
                        .permitAll())

기본 로그인 폼을 사용한다고 선언하는 로직이다.

 

그럼 구조를 확장시켜서 사용자 정보를 DB에서 불러오기를 해보겠다.

일단 DB에서 불러오려면

User엔티티와 사용자 정보 조회 서비스 인터페이스, 비밀번호 암호화 하는 인코딩 파일

이렇게 3가지가 필요하다.

  • User Entity
  • UserDetailService
  • BCryptPasswordEncoder

Member.java

package com.example.security.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import lombok.Data;

@Entity
@Data
public class Member {
    @Id
    String username;

    String password;
}

엔티티파일이다.

 

MemberRepository.java

package com.example.security.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.example.security.entity.Member;

public interface MemberRepository extends JpaRepository<Member, String> {

}

멤버 엔티티를 Jpa를 통해서 DB에 접근시키는 파일이다.

 

MemberDetailsService.java

package com.example.security.service;

import org.springframework.security.core.userdetails.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;

import com.example.security.entity.Member;
import com.example.security.repository.MemberRepository;

import java.util.List;

@Service
public class MemberDetailsService implements UserDetailsService {
    @Autowired
    MemberRepository memberRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Member member = memberRepository.findById(username)
                .orElseThrow(() -> new UsernameNotFoundException("사용자 없음: " + username));
        return new User(
                member.getUsername(),
                member.getPassword(),
                List.of(new SimpleGrantedAuthority( "ROLE_USER" )));
    }
}

 

이렇게 설정을 했으면

DB에 다음 값을 넣어준다.

/hello의 경로는 누구나 접근이 가능한 것을 볼 수 있다.

/admin경로로 접근 시 login페이지로 리디랙션 되는 것을 볼 수 있다.

그럼 해당 아이디 패스워드를 입력해보겠다.

아이디 패스워드를 사용해서 입력하고 로그인 하고 

admin경로로 들어가보면 관리자 전용 페이지 라고 뜨는 것을 볼 수 있다.

만약 로그인 실패 시 주소창에 빨간 메시지와 함께 ?error주소도 같이 나타난다.

로그아웃 처리 시 

Config파일에

.logout(logout -> logout
                .logoutUrl("/logout") // default: /logout (POST)
                .logoutSuccessUrl("/login?logout=true")
                .invalidateHttpSession(true) // 세션 제거
                .deleteCookies("JSESSIONID") // 쿠키 제거
               
)

http객체 메서드의 logout메서드를 사용해서 

/logout경로 로 POST방식으로 접근 시 /login?logout=true를 반환하면서 세션과 쿠키를 제거해준다.

로그아웃 시 

다음과 같이 ?logout=true로 설정이 되는 것을 볼 수 있다.

 

세션을 유지(자동 로그인)시키려면

.rememberMe(r -> r
 .key("remember-me-key") // 서버 비밀키
 .rememberMeParameter("remember-me") // form 체크박스 name
 .tokenValiditySeconds(60 * 60 * 24 * 7) // 7일
)
;

rememberMe메서드를 사용해서 세션을 유지시켜준다. 

필자는 60 * 60 * 24 * 7 로 7일을 유지시켜주는 세션을 만들었다.

로그인 페이지에서 자동 로그인 remember-me이름으로 보내주는 체크박스를 만들어줬다.

이렇게 자동로그인 체크박스를 선택하고 로그인을 하면 별도로 remember-me라는 쿠키가

생성되는 것을 볼 수 있다.

 

권한별 접근제어 

페이지에 권한별로 접근을 제어하려면 엔티티에 ROLE을 추가해 관리자와 사용자를 나눠주는 역할을 하는

칼럼을 생성해야한다.

    private String role;

다음과 같이 생성해주고

.requestMatchers("/admin-page").hasRole("ADMIN")// hasRole이 authenticated보다 강력하다.
.requestMatchers("/user-page").hasRole("USER")

requestMatchers로 admin-page와 user-page의 접근권한을 "ADMIN"으로 등록된 계정과

USER로 등록된 계정을 따로 관리를 해주는 것이다.

 

그리고 MemberDetailsService에

                List.of(new SimpleGrantedAuthority(member.getRole())));

member.getRole로 접근해서 ADMIN인지 USER인지 확인한다.

 

그럼 필자는 ROLE이 USER인 계정으로 로그인 해서 /admin-page와 /user-page둘 다 접근해보겠다.

user-page에는 접근이 되는 것을 볼 수 있다.

/admin-page로 접근시 Error가 뜨는 것을 볼 수 있는데

Forbidden은 금지된 이라는 뜻을 가지고 있다.

403 Forbidden오류는 서버가 요청한 웹 페이지에 대해서 권한이 없다고 판단할 때 나타나는 상태코드이다.

그럼 우리는 ROLE이 잘 적용된 것을 알 수 있다.

728x90
반응형
LIST

'Spring' 카테고리의 다른 글

스프링부트 - CORS / CSRF  (0) 2025.05.15
스프링부트 - 타임리프(Thymeleaf)  (1) 2025.05.13
스프링부트 - JWT(Json Web Token)이란?  (0) 2025.05.11
스프링부트 - 파일 업로드  (0) 2025.05.10
스프링부트 - 필터(FilterRegistrationBean)  (0) 2025.05.10
'Spring' 카테고리의 다른 글
  • 스프링부트 - CORS / CSRF
  • 스프링부트 - 타임리프(Thymeleaf)
  • 스프링부트 - JWT(Json Web Token)이란?
  • 스프링부트 - 파일 업로드
코린이 파닥거리기
코린이 파닥거리기
    반응형
    250x250
  • 코린이 파닥거리기
    코린이 파닥거리기의 블로그
    코린이 파닥거리기
  • 전체
    오늘
    어제
    • 분류 전체보기 (128) N
      • 백준[파이썬] (56) N
      • Spring (31)
      • CS (1)
      • 자바 (4)
      • 백준[자바] (20)
      • 프로그래머스 (5)
      • 토이프로젝트 (1)
      • SWEA (2)
      • MSA (7) N
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    코딩테스트
    AOP
    재귀
    스프링부트
    테스트코드
    Java
    스프링 클라우드
    스프링 부트와 AWS로 혼자 구현하는 웹 서비스
    spring
    SpringBoot
    JPA
    파이썬
    SWEA
    백준
    프로그래머스
    자바
    누적합
    JWT
    MSA
    스프링
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
코린이 파닥거리기
스프링부트 - 스프링 시큐리티
상단으로

티스토리툴바