Developer Note/국비과정 수업내용 정리&저장

24년 11월 19일

DH_PARK 2024. 11. 25. 03:02

능력단위평가 시험일

요구사항 확인

내가 맡은 부분 : 유스케이스 , 유스케이스 명세서

그리고 어차피 나중에 진행하게 될 프로젝트이기 때문에 user부분에 대한 코드작성을 맡았다.


오후부터는 드디어 스프링 시큐리티 시작 !

Spring Security 란 ?

Spring Security는 애플리케이션의 **인증(authentication)**과 **인가(authorization)**를 제공하는 강력하고 유연한 프레임워크입니다.

Spring 생태계의 일부로, 웹 애플리케이션뿐 아니라 다양한 Spring 기반 애플리케이션에서 보안을 강화하는 데 사용됩니다.

Spring Security는 엔터프라이즈급 보안을 쉽게 구현할 수 있도록 설계되어 있으며, 다양한 보안 요구사항을 지원합니다.

스프링 시큐리티는 필터 기반으로 동작한다.

스프링에서 가장 중요한 파트인 스프링 시큐리티다…

의존성 추가

Maven Repository 에서 의존성을 다운받는다.

core , web , config ,taglibs 4개 다운받음.

		<!-- SPRING SECURITY -->
		<dependency>
		    <groupId>org.springframework.security</groupId>
		    <artifactId>spring-security-core</artifactId>
		    <version>${org.springframework-version}</version>
		</dependency>
		<dependency>
		    <groupId>org.springframework.security</groupId>
		    <artifactId>spring-security-web</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<dependency>
		    <groupId>org.springframework.security</groupId>
		    <artifactId>spring-security-config</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<dependency>
		    <groupId>org.springframework.security</groupId>
		    <artifactId>spring-security-taglibs</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>

4가지 의존추가 해준다.

버전은 스프링의 버전과 똑같이 맞춰준다.

Web.xml 설정

  <!-- Security 기능 제공 -->
	<filter>
		<filter-name>springSecurityFilterChain</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	</filter>
    <filter-mapping>
		<filter-name>springSecurityFilterChain</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

📌 주의 사항!!

  • multipartFilter는 파일 업로드 요청을 처리하기 때문에 springSecurityFilterChain 보다 먼저 실행되어야 해서 위에 작성해줍니다.
  • 그 다음 인코딩을 진행해야 하고,
  • springSecurityFilterChain을 작성해줍니다.

SpringSecurityFilterChain 필터

springSecurityFilterChain filter

  • DelegatingFilterProxy 클래스를 사용하여 구현
    • Spring Security 필터를 사용하는 시작점으로 설정되며, 서블릿 컨테이너 영역(WAS)의 필터와 Spring Container에서 Spring Bean으로 등록된 필터를 연결하는 역할을 합니다.
  • 기능
    • 인증(Authentication) : 사용자의 인증을 처리합니다.
    • 인가(Authorization) : 사용자의 권한을 확인합니다.
    • 보안 : 사용자의 요청을 보호합니다

그리고 Configuration 파일을 만들고 난 후에

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{

	
}

프로젝트를 실행해보면 … ?

시큐리티 기본 login page

로그인 페이지를 따로 만들지 않아도 자동으로 프로젝트를 실행하니 이런 창이 나옴 !

(스프링 시큐리티를 사용하면 기본적으로 생성되는 창이라고함!)

근데 로그인 페이지를 따로 만들긴 해야함.

이 페이지는 커스텀이 불가능하기 때문에 결국 로그인페이지를 만들어야 한다고 한다.


 

Spring Security 설정

스프링 시큐리티를 사용하려면 이 설정이 가장 중요하다!

아니 그냥 시큐리티는 애초에 설정을 하는 작업이다.

@Configuration
@EnableWebSecurity
public class SecurityConfig  extends WebSecurityConfigurerAdapter{
	
	@Autowired
	private PasswordEncoder passwordEncoder;
	
	@Autowired
	private PrincipalDetailsServiceImpl principalDetailsServiceImpl;
	
	@Autowired
	private DataSource dataSource;
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		
		//권한체크
		http.authorizeRequests()
			.antMatchers("/","/join").permitAll()
			.antMatchers("/user").hasRole("USER")
			.antMatchers("/member").hasRole("MEMBER")
			.antMatchers("/admin").hasRole("ADMIN")
			.anyRequest().authenticated();
		
		//로그인
		http.formLogin()	//로그인 설정을 구성하는 부분
			.loginPage("/login")	//기본 로그인 페이지를 지정
			.permitAll()			
			.successHandler(new CustomLoginSucccessHandler())	//로그인이 성공했을 때의 핸들러	  //이런건 직접 정의하는 객체인듯 ?
			.failureHandler(new CustomAuthenticationFailureHandler());	//로그인 실패시 처리
		
		
		
		//로그아웃
		http.logout()
			.permitAll()
			.addLogoutHandler(new CustomLogoutHandler())				//로그아웃시의 핸들러
			.logoutSuccessHandler(new CustomLogoutSuccessHandler());	//로그아웃 성공시의 핸들러
			
		
		
		//예외처리
		http.exceptionHandling()
			.authenticationEntryPoint(new CustomAuthenticationEntryPoint())		//미인증 사용자 예외처리
			.accessDeniedHandler(new CustomAccessDeniedHandler());				//권한 실패(부족)시 예외처리 , 더 높은 권한으로 접근하려 할 때 예외처리
		
		
		//REMEMBER_ME
		http.rememberMe()
			.key("rememberMeKey") //사용자 키 값
			.rememberMeParameter("remember-me")	//파라미터 값	
			.alwaysRemember(false)  //항상 리멤버미 기능을 사용할지 여부
			.tokenValiditySeconds(60*60)  //리멤버미 기능 유지시간
			.tokenRepository(tokenRepository());	//토큰 저장소를 설정
	}

	
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		
//		auth.inMemoryAuthentication()
//			.withUser("user")
//			.password(passwordEncoder.encode("1234"))
//			.roles("USER");
//		
//		auth.inMemoryAuthentication()
//			.withUser("member")
//			.password(passwordEncoder.encode("1234"))
//			.roles("MEMBER");
//		
//		auth.inMemoryAuthentication()
//			.withUser("admin")
//			.password(passwordEncoder.encode("1234"))
//			.roles("ADMIN");
		
		auth.userDetailsService(principalDetailsServiceImpl).passwordEncoder(passwordEncoder);
		
	}
	
	
	@Bean
	public PasswordEncoder passwordEncoder() {		
		return new BCryptPasswordEncoder();
	}		

	@Bean
	public PersistentTokenRepository tokenRepository() {
		JdbcTokenRepositoryImpl repo = new JdbcTokenRepositoryImpl();
		repo.setDataSource(dataSource);
		return repo;
	}
	
		
	
}

시큐리티 설정 파일에서 .formlogin.loginPage(”/login”) 처럼 커스텀 페이지를 설정한 경우라면 기본 로그인폼이 보이지 않게 된다.

SpringSecurity 에서 쓰는 메서드

  • permitAll() : 인증되지 않은 모든 사용자를 허용하는 메서드
    • / 와 /join 페이지는 모든 사용자가 접근할 수 있게한다
  • 밑으로 user , member , admin 각 주소는 ROLE이 맞을 경우에만 접근할 수 있도록한다.
    • hasRole : 메서드를 사용하면 앞에 자동으로 ROLE_ 이라는 접두사가 붙는다.
    • (비슷한 코드로 .antMatchers("/user").hasAuthority("ROLE_USER") 가 있다.

anyRequest().authenticated()

  • 위에서 지정된 경로 이외의 모든 요청은 인증된 사용자만 접근할 수 있습니다.
  • 인증되지 않은 사용자는 접근이 차단되며 로그인 페이지로 리다이렉트됩니다.
	@Autowired
	private PasswordEncoder passwordEncoder;
	
	public void memberJoin(UserDto userDto) {
		userDto.setPassword(passwordEncoder.encode(userDto.getPassword()));
		userMapper.Insert(userDto);
	}

비밀번호를 암호화 하는 코드

이거는 웬만해서 기본적으로 사용해야 하는 부분인듯.


jsp 파일에서 jstl 사용

  <%@ taglib uri="<http://www.springframework.org/security/tags>" prefix="sec"%>

Spring Security에서 제공하는 JSP 커스텀 태그 라이브러리를 선언하는 태그입니다.

이 태그를 선언해서 jstl 을 사용할 수 있게 한다.

User 페이지

	<h1>USER !!</h1>
	
	<!-- getter를 걸어놓아서 pricipal을 가져올 수 있어요 -->
 	<p>principal : <sec:authentication property="principal"/></p><hr/>
 	<p>UserDto : <sec:authentication property="principal.userDto"/></p><hr/>
 	<p>principal로 꺼낸 ID : <sec:authentication property="principal.Username"/></p><hr/>
 	<p>사용자의 이름 : <sec:authentication property="principal.userDto.username"/></p><hr/>
 	<p>사용자의 아이디 : <sec:authentication property="principal.userDto.username"/></p><hr/>
 	<p>사용자의 권한 목록 : <sec:authentication property="principal.userDto.role"/></p><hr/>	

해석 :

<p>UserDto : <sec:authentication property="principal.userDto"/></p>

이 부분은 principal 객체에서 Username 필드를 출력하는 부분이다.

여기서 principal 객체가 뭔지 알아야 할 것 같다.

Principal 객체란 ?

스프링 시큐리티에서 현재 인증된 사용자를 나타내는 객체이다.

로그인을 해야만 생성되는 객체이기 때문에 로그인 하지 않은 상태에서 사용하면 null 값이 들어가는데.

지금 이 User 페이지는 Controller를 통해서 로그인을 User Role 로 했을 시에 진입할 수 있는 user 페이지이기 때문에 principal 안에 있는 username 을 getUsername() 메서드를 통해서 사용자 ID 를 받는다.

이 principal 은 UserDetails 인터페이스를 구현한 객체라고 하는데 여기서 또 UserDetails 인터페이스는 뭘까 ?

UserDetails 란?

Spring Security에서 사용자의 정보를 담는 인터페이스이다.

사용자 인증 및 권한 관리에서 사용되며, 로그인 시 DB나 외부 서비스에서 사용자 정보를 로드할 때 주로 사용된다.


CSRF 공격이란 ?

CSRF (Cross-site request forgery) : 웹 애플리케이션 취약점 중 하나로 사용자가 자신의 의지와 무관하게 공격자가 의도한 행동을 하여 특정 웹페이지를 보안에 취약하게 한다거나 수정, 삭제 등의 작업을 하게 만드는 공격방법을 의미한다. 유명 경매 사이트 옥션의 개인정보 유출 사건에 사용된 공격 방식이다.

<input type="hidden" name="_csrf" value="${_csrf.token}">
  • 사용자가 로그인 폼을 제출할 때 _csrf 필드에 포함된 값이 서버로 전송됩니다.
  • 서버는 이 값을 검증하여 요청이 정상적인 사용자의 요청인지 확인합니다.

지금 시점으로 스프링 최신버전 6.2.0

스프링이 5.7 버전 이상부터는 WebSecurityConfigurerAdapter 클래스를 더 이상 지원하지 않는다고 한다. !

하지만 우리 수업에서는 스프링 버전이 5.0.7 버전을 사용하고 있다.

일단 지금은 이 클래스를 사용하겠지만 나중에는 새로운 클래스를 사용하는 방법을 알아서 사용해야 되겠다 !

'Developer Note > 국비과정 수업내용 정리&저장' 카테고리의 다른 글

24년 11월 21일  (3) 2024.11.25
24년 11월 20일  (0) 2024.11.25
24년 11월 18일  (0) 2024.11.24
24년 11월 15일  (0) 2024.11.24
24년 11월 14일  (0) 2024.11.24