[TIL] 22.12.29 스프링 어노테이션 인식이 안될 때 또는 인텔리제이 프로젝트 인식 안될때,라이브러리 인식 안될때 에러 , 스프링공부

hyewon jeong·2022년 12월 29일
0

TIL

목록 보기
56/138

이 글을 쓴 이유는 수차례 같은 에러로 인해 프로젝트를 새로 작성하고 깃허브 저장소도 새로 만들기를 반복한 끝에 ! 언제까지 새로 만들 수 없다!! 해서 구글링과 튜터님의 도움으로 드디어 해결 되었다.🤗 정말 ......별거 아니였다 ㅠㅠㅋㅋㅋㅋ 별거아닌 것으로 저 처럼 고생하고 있을 누군가를 위해 기록한다.😂

1 발생

매번 깃허브에 프로젝트를 푸시하고 다른 컴퓨터에서 풀 하는 과정에서 , 자바클래스들이 이름모를 'J'파일로 바껴지면서 에러로 만신창이가 된 프로젝트를 마주하게 됐다.

2 코드

'j'파일로 바껴져 에러현상

점섬으로 생겨진 에러현상

@어노테이션에러 현상

프로젝트를 풀로 받자마자 이런 현상을 보고 SDK 설치하라는 문구를 보고 설치를 한다.
해당 버전으로 해도 ㅠㅠ 오류는 여전했다.

3 원인

  • 3가지 현상들은 결국 라이브러리(dependencies)들이 제 기능을 하지 못한다는 것

4 해결

  • 인텔리제이 기준으로 build.gradle에서 빨간 박스의 돌고래 표시(Load Gradle Changes) (단축키 ctrl + shift + O)를 눌러준다.
    저 표시는 라이브러리들이나 환경세팅이 변경됐을 경우 그 세팅에 맞게 프로젝트를 설정해주는 기능이다.

  • 또는 간혹 돌고래 표시가 안 뜰때도 있다. 그럴 때는 build.gradle 창에서 오른쪽 마우스 - [linked Gradle Project] 클릭 후 로딩을 기다리면 ~ ^^ ㅎㅎ 해결🎉

  • 해결

5 오늘 알게 된 점

@AuthenticationPrincipal

스프링 시큐리티는 SecurityContext에 인증된 Authentication 객체를 넣어두고 현재 스레드 내에서 공유되도록 관리하고 있는데요.

아래는 SecurityContext 인터페이스에 기재된 주석의 일부를 발췌했습니다.
(SecurirtContext : Interface defining the minimum security information associated with the current thread of execution.)

인증이후 편의적으로 현재 인증된 세션유저를 가져오기 위해 @AuthenticationPrincipal 어노테이션을 통해 UserDetails 인터페이스를 구현한 유저 객체를 주입할 때 사용하는 편입니다.

🔥 즉, 'JWT 토큰과 Custom Security Filter를 통해 사용자를 로그인이 된 상태로 유지시켜준다' 라고 이해하면 된다.

Spring Security 로그인 페이지 url 설정시 유의할 점 /login-page

    @ResponseBody
    @PostMapping("/login-page")
    public String login(@RequestBody LoginRequestDto loginRequestDto, HttpServletResponse response) {
        userService.login(loginRequestDto, response);
        return "success";

🔥 기본적으로 GetMapping의 로그인을 Security에서 사용을 하고 있기 때문에 충돌이 발생한다.

그래서 /login-page로 바꿔준다.

Spring Security 기본 설정

스프링 프레임워크 추가 build Gradle

// 스프링 시큐리티
implementation 'org.springframework.boot:spring-boot-starter-security'

WebSecurityConfig.java

package com.sparta.myselectshop.config;


import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@RequiredArgsConstructor
@EnableWebSecurity // 스프링 Security 지원을 가능하게 함
@EnableGlobalMethodSecurity(securedEnabled = true) // @Secured 어노테이션 활성화
public class WebSecurityConfig {
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        // h2-console 사용 및 resources 접근 허용 설정
        return (web) -> web.ignoring()
                .requestMatchers(PathRequest.toH2Console())
                .requestMatchers(PathRequest.toStaticResources().atCommonLocations());
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf().disable();

        http.authorizeRequests().antMatchers("/api/user/**").permitAll()
                .antMatchers("/api/search").permitAll()
                .antMatchers("/api/shop").permitAll()
                .anyRequest().authenticated();

        http.formLogin().loginPage("/api/user/login-page").permitAll();

        http.exceptionHandling().accessDeniedPage("/api/user/forbidden");

        return http.build();
    }

}

SecurityExceptionDto.java

package com.sparta.myselectshop.dto;

import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class SecurityExceptionDto {

    private int statusCode;
    private String msg;

    public SecurityExceptionDto(int statusCode, String msg) {
        this.statusCode = statusCode;
        this.msg = msg;
    }
}

UserController.java 일부

@GetMapping("/forbidden")
    public ModelAndView getForbidden() {
        return new ModelAndView("forbidden");
    }

    @PostMapping("/forbidden")
    public ModelAndView postForbidden() {
        return new ModelAndView("forbidden");
    }

SpringBoot 3v 변경된 코드 확인 antMatchers() → requestMatchers()

@Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf().disable();

        http.authorizeHttpRequests().requestMatchers("/api/user/**").permitAll()
                .requestMatchers("/api/search").permitAll()
                .requestMatchers("/api/shop").permitAll()
                .anyRequest().authenticated();

        http.formLogin().loginPage("/api/user/login-page").permitAll();

        http.exceptionHandling().accessDeniedPage("/api/user/forbidden");

        return http.build();
    }

Stateless

stateless : server side에 client와 server의 동작, 상태정보를 저장하지 않는 형태, server의 응답이 client와의 세션 상태와 독립적임

OncePerRequestFilter

문서에 의하면

Filter base class that aims to guarantee a single execution per request dispatch, on any servlet container. It provides a doFilterInternal method with HttpServletRequest and HttpServletResponse arguments.

어느 서블릿 컨테이너에서나 요청 당 한 번의 실행을 보장하는 것을 목표로 한다.
doFilterInternal메소드와 HttpServletRequest와 HttpServletResponse인자를 제공한다.

인증 또는 인가를 거치고나서 특정 url로 포워딩하면, 요청이 들어왔으니 인증 및 인가필터를 다시 실행시켜야 하지만, OncePerRequestFilter를 사용함으로써 인증이나 인가를 한번만 거치고 다음 로직을 진행할 수 있도록 한다.

profile
개발자꿈나무

2개의 댓글

comment-user-thumbnail
2022년 12월 30일

혜원님 다 옮기신거예요? 대단해요......!!!
너무 야무지게 잘 옮겨주셔가지고 제가 그동안 못달았던 것들까지 저도 참고해보겠습니다!!

한 해 마무리 잘하시고 저와는 또 내년에 만나요 : >

1개의 답글