[spring boot] Spring Security

2024. 11. 18. 14:50·SPRING BOOT

Spring Security는 강력한 인증 및 인가 기능을 제공하여 웹 애플리케이션의 보안을 효과적으로 관리한다. 유연한 보안 설정과 다양한 인증 방식을 지원하며, CSRF(Cross-Site Request Forgery는 공격자가 사용자의 브라우저를 속여서 사용자가 의도하지 않은 요청을 실행하도록 만드는 공격) 보호 및 비밀번호 암호화 기능을 통해 안전성을 강화한다. 이때, interceptor는 요청과 응답을 가로채어 로깅, 성능 모니터링 등을 수행하는 데 사용되지만, 애플리케이션의 보안 기능에는 영향을 주지 않는다. 따라서 보안 요구 사항에 따라 Spring Security만으로도 충분히 안전한 애플리케이션을 구축할 수 있게 된다.

전체적인 흐름은 다음과 같다.

 

1.WebSecurityConfig

    @Bean
    public WebSecurityCustomizer configure() {
        return (web) -> web.ignoring()
                .requestMatchers(PathRequest.toH2Console())
                .requestMatchers("/static/**", "/index.html", "/");
    }

.authorizeHttpRequests(auth -> auth

  • return (web) -> web.ignoring()  : 특정 요청을 스프링 시큐리티의 인증 및 인가 처리에서 제외
  • requestMatchers( )  : 요청이나 경로를 제외한다.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/", "/index.html", "/login", "/signup", "/user").permitAll()
            .requestMatchers("/home").authenticated()
            .anyRequest().authenticated()
        )
        .formLogin(form -> form
            .loginPage("/login")
            .loginProcessingUrl("/login")
            .defaultSuccessUrl("/home", true)
            .failureUrl("/login?error=true")
            .permitAll()
        )
        .logout(logout -> logout
            .logoutSuccessUrl("/login")
            .invalidateHttpSession(true)
        )
        .csrf(csrf -> csrf.disable());

    return http.build();
}
  • .authorizeHttpRequests(auth -> auth) : 특정 경로에 대해 인증 및 접근 권한을 설정한다.
로그인 설정
  • permitAll() : 모든 사용자가 접근 가능.(괄호안의 경로는 로그인 가능)
  • authenticated() : 인증된 사용자만 접근 가능 (∴/home은 로그인이 필수이다.)
  • anyRequest() : 위에서 지정되지 않은 모든 경로는 인증 필요.
  • loginPage("/login"): Get방식, 사용자가 로그인할 페이지 경로를 지정.(컨트롤러 주소)
  • loginProcessingUrl("/login"): Put방식, 로그인 요청을 처리하는 URL.
  • defaultSuccessUrl("/home", true): 로그인 성공 후 강제로 /home으로 리다이렉션한다.
  • failureUrl("/login?error=true"): 로그인 실패 시 다시 로그인 페이지로 리다이렉션한다.
로그아웃 설정

 

  • logoutSuccessUrl("/login"): 로그아웃 후 /login으로 이동.
  • invalidateHttpSession(true): 세션 무효화.
csrf.disable(): CSRF비활성화
@Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
    DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
    provider.setUserDetailsService(userService);
    provider.setPasswordEncoder(bCryptPasswordEncoder());
    provider.setHideUserNotFoundExceptions(false);
    return provider;
}
  • AuthenticationManager는 인증 시도 시 생성된 UsernamePasswordAuthenticationToken 객체를 받아 인증 절차를 시작한다. 이 과정에서 AuthenticationManager는 DaoAuthenticationProvider를 사용하여 데이터베이스 기반 인증을 처리한다.
  • setUserDetailService: 사용자 정보를 로드하는 데 사용하낟.
  • passwordEncoder: 비밀번호 암호화 및 검증 처리.
  • setHideUserNotFoundExceptions(false) : 사용자 미존재 시 예외를 표시하여 디버깅 정볼르 추가로 확인할 수 있도록 예외 핸들러를 추가한다.
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
    return new BCryptPasswordEncoder();
}

: 비밀번호 암호화시 인콛러로 사용할 빈 등록

 

2.User(Entity)

@Entity
@Table(name = "users")
@Getter
@Setter
@NoArgsConstructor
@Builder
public class User implements UserDetails {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, unique = true)
    private String email;

    private String password;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return List.of(new SimpleGrantedAuthority("user"));
    }

    // 이하 생략...
}
  • @Entity: 이 클래스는 데이터베이스의 users 테이블과 매핑됨. MyBatis와 비슷한 역할
  • UserDetails 구현: Spring Security에서 사용자 인증 정보를 관리하는 표준 인터페이스.
  • 권한 (getAuthorities): 기본적으로 "user" 권한을 부여.

3.UserRepository

public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByEmail(String email);
}
  • JpaRepository: CRUD 및 쿼리 메서드를 제공.(Mapper와 비슷한 역)
  • findByEmail: 이메일(username)을 기준으로 사용자 검색.

4.UserDetailService

@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
    User user = userRepository.findByEmail(email)
        .orElseThrow(() -> new UsernameNotFoundException("사용자를 찾을 수 없습니다: " + email));
    return User.builder()
        .email(user.getEmail())
        .password(user.getPassword())
        .build();
}

 

  • email로 사용자 정보 조회.(이때, springsecruriy에서는 username이 id로 통용되는 의미이며, 이 예제에서는 email로 id를 선언했다.)
  • 예외 처리: 사용자 미존재 시 UsernameNotFoundException 발생.
  • 주의사항: return시 builder()로 시작했으면 build()로 종료해야함.

5. UserService

public void save(AddUserRequest request) {
    User user = User.builder()
        .email(request.getEmail())
        .password(passwordEncoder.encode(request.getPassword()))
        .build();
    userRepository.save(user);
}

 

  • .password(passwordEncoder.encode(request.getPassword())) : 비밀번호를 인코딩해 암호화
  • userRepository.save(user); : 요청을 받아 데이터베이스에 저장하고 사용자 생성

6.UserApiController

@PostMapping("/user")
public String signup(AddUserRequest request) {
    userService.save(request);
    return "redirect:/login";
}
  • AddUserRequest를 받아 사용자 생성

7.UserViewController

    @GetMapping("/home")
    public String home(Model model,
    		@AuthenticationPrincipal User userInfo) throws Exception {
        model.addAttribute("userInfo", userInfo);
        return "home";
    }
    
    @GetMapping("/logout")
    public String logout(HttpServletRequest request, HttpServletResponse response) {
        new SecurityContextLogoutHandler().logout(request, response,
                SecurityContextHolder.getContext().getAuthentication());
        return "redirect:/login";
    }
  • Spring Security는 로그인 성공 시 **SecurityContext**에 사용자의 인증 정보를 저장한다. 이 정보는 **Principal**이라는 객체에 저장되며, Spring Security는 이 객체를 통해 사용자 정보를 관리한다. @AuthenticationPrincipal을 사용하면, Spring Security가 자동으로 현재 로그인한 사용자 객체를 메서드 파라미터로 주입한다.

8.Tymeleaf 템플릿

<html xmlns:th="http://www.thymeleaf.org">
  <body>
    <div class="main-container">
        <h1>로그인 성공!</h1>
        <p>놀랍지만 메인 페이지입니다.</p>
        <div>
		<span th:text="${userInfo.email} 님 환영합니다."></span>
		<br>
		    <span th:if="${userInfo.password} != null"  
		    	th:text="${userInfo.password}  !!! 비번 유출 주의"></span>
		</div>
		<button type="button" class="btn btn-secondary" onclick="location.href='/logout'">로그아웃</button>
		</body>
    </div>
</body>
</html>
  • ${userInfo.email} : EL 
  • |...| (파이프 기호): Thymeleaf에서 문자열 리터럴을 감싸는 구문이다. 이 기호를 사용하여 문자열 내부에서 EL을 간단하게 사용할 수 있다.
  • 즉, "| |" 사이의 내용은 문자열로 인식되며, ${...} 형태의 표현식을 포함할 수 있다.

참고: https://innovation123.tistory.com/38#2)%20%5B%5B%E2%80%A6%5D%5D-1

 

[Thymeleaf] 기본 문법 (text, 변수표현, URL 링크, 리터럴)

텍스트 - text, utext 1. 내용 변경 : th:text , [[…]] "th:text" 사용 : 텍스트 컨텐츠 안에서 직접 출력하기 : [[${data}]] 1) th:text 내용의 값을 th:text 의 값으로 변경한다. 여기서는 ‘텍스트’을 ${data} 의 값

innovation123.tistory.com

 

전체적인 흐름

'SPRING BOOT' 카테고리의 다른 글

restserver,restclient  (0) 2024.11.16
[spring boot]RestApi  (0) 2024.11.12
[spring boot] HTTP호출방식  (0) 2024.11.11
[spring boot] JPA와 H2 데이터베이스로 간단한 게시판 만들기  (0) 2024.11.09
[spring boot] 머스태치(mustache)/JPA  (0) 2024.11.08
'SPRING BOOT' 카테고리의 다른 글
  • restserver,restclient
  • [spring boot]RestApi
  • [spring boot] HTTP호출방식
  • [spring boot] JPA와 H2 데이터베이스로 간단한 게시판 만들기
라텐느
라텐느
이제 막 개발을 시작한 초보가 개인공부를 하는 공간입니다.
  • 라텐느
    괴발개발
    라텐느
    • 개발자 (153)
      • HTML|CSS (14)
      • JAVA (29)
      • JAVACSCRIPT (15)
      • SQL (16)
      • 기타 (5)
      • JSP (2)
      • SPRING (13)
      • SPRING BOOT (6)
      • Git&GitHub (1)
      • 시행착오 (2)
      • 개발일지 (35)
        • GreenMiniProject1 (12)
        • GreenMiniProject2 (9)
        • GreenFinalProject (14)
      • Flutter (5)
      • 자격증 (0)
        • SQLD (1)
      • AWS (2)
      • Linux (1)
      • 자료구조&알고리즘 (4)
  • 블로그 메뉴

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

    • GitHub
  • 공지사항

  • 인기 글

  • 태그

    input
    부트캠프
    JQuery
    link
    오블완
    javascript
    CSS
    개발자
    태그
    tag
    자기계발
    AJAX
    HTML
    SQL
    db
    java
    링크
    JS
    티스토리챌린지
    일지
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
라텐느
[spring boot] Spring Security
상단으로

티스토리툴바