15. 스프링 시큐리티 애너테이션

책의 15. 스프링 시큐리티 애너테이션 의 내용

SecurityConfig.java

package com.mysite.config;

import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
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.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import com.mysite.common.security.CustomAccessDeniedHandler;
import com.mysite.common.security.CustomLoginSuccessHandler;
import lombok.extern.slf4j.Slf4j;

@Configuration
@Slf4j
//시큐리티 애너테이션 활성화를 위한 설정
@EnableMethodSecurity(prePostEnabled=true, securedEnabled=true)
public class SecurityConfig {
	
	@Autowired
	DataSource datasource;
	
	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		log.info("security config...");
		
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/board/read")
				.permitAll());		
		
		
		//사용자가 직접 정의한 로그인 페이지의 URI를 지정한다.
		http.formLogin()
			.loginPage("/login")
			.permitAll()
			.successHandler(authenticationSuccessHandler());
		
		//접근 거부 처리자의 URI 지정
		http.authorizeHttpRequests((authorize) -> authorize
				// Allow access to the "/accessError" page
				.requestMatchers("/accessError").permitAll() 
	            .anyRequest().authenticated()
	        )
	        .exceptionHandling((except) -> except
	            .accessDeniedHandler(accessDeniedHandler())
	        );
		//로그아웃 처리를 위한 URI를 지정하고, 로그아웃 후에 세션을 무효화한다.
		http.logout().logoutUrl("/logout").invalidateHttpSession(true);

		//데이터소스를 지정하고 테이블을 이용해서 기존 로그인 정보를 기록
		http.rememberMe()
			// 랜덤한 키 값
			.key("random")
			.tokenRepository(createJDBCRepository())
			//쿠키의 유효시간을 지정한다.
			.tokenValiditySeconds(60*60*24);	
		
		return http.build();
		
	}
	

	@Bean
	public AccessDeniedHandler accessDeniedHandler() {
		return new CustomAccessDeniedHandler();
	}
	
	@Bean
	public AuthenticationSuccessHandler authenticationSuccessHandler() {
		return new CustomLoginSuccessHandler();
	}
	
	// PersistentTokenRepository 구현 클래스 객체 생성
	private PersistentTokenRepository createJDBCRepository() {
		JdbcTokenRepositoryImpl repo = new JdbcTokenRepositoryImpl();
		repo.setDataSource(datasource);
		return repo;
	}
	
}

@PreAuthorize("hasRole('MEMBER')") 은 자동으로 ROLE_MEMBER로 변경해서 권한을 확인한다고 한다.

ROLE_MEMBER는 권한 DB에서 정의한 것으로 ROLE_TEST 이런식으로 DB에 설정하면, @PreAuthorize("hasRole('TEST')") 라고 사용할 수 있다.

 

/board/read 경로에 permitAll으로 전체 접근이 가능하게 했지만, @PreAuthorize("isAuthenticated()") 이 어노테이션이 있으면, 로그인해야만 접근이 가능하다.

반응형

댓글()

14. 자동 로그인

책의 14. 자동 로그인 의 내용

SecurityConfig.java

package com.mysite.config;

import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import com.mysite.common.security.CustomAccessDeniedHandler;
import com.mysite.common.security.CustomLoginSuccessHandler;
import lombok.extern.slf4j.Slf4j;

@Configuration
@Slf4j
public class SecurityConfig {
	
	@Autowired
	DataSource datasource;
	
	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		log.info("security config...");
		
		//URI 패턴으로 접근 제한을 설정한다.
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/board/list")
				.permitAll());
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/board/register")
				.hasRole("MEMBER"));
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/notice/list")
				.permitAll());
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/notice/register")
				.hasRole("ADMIN"));
		http.authorizeHttpRequests((auth)->auth
				.requestMatchers("/home")
				.permitAll());
		
		//사용자가 직접 정의한 로그인 페이지의 URI를 지정한다.
		http.formLogin()
			.loginPage("/login")
			.permitAll()
			.successHandler(authenticationSuccessHandler());
		
		//접근 거부 처리자의 URI 지정
		http.authorizeHttpRequests((authorize) -> authorize
				// Allow access to the "/accessError" page
				.requestMatchers("/accessError").permitAll() 
	            .anyRequest().authenticated()
	        )
	        .exceptionHandling((except) -> except
	            .accessDeniedHandler(accessDeniedHandler())
	        );
		//로그아웃 처리를 위한 URI를 지정하고, 로그아웃 후에 세션을 무효화한다.
		http.logout().logoutUrl("/logout").invalidateHttpSession(true);

		//데이터소스를 지정하고 테이블을 이용해서 기존 로그인 정보를 기록
		http.rememberMe()
			// 랜덤한 키 값
			.key("random")
			.tokenRepository(createJDBCRepository())
			//쿠키의 유효시간을 지정한다.
			.tokenValiditySeconds(60*60*24);	
		
		return http.build();
		
	}
	

	@Bean
	public AccessDeniedHandler accessDeniedHandler() {
		return new CustomAccessDeniedHandler();
	}
	
	@Bean
	public AuthenticationSuccessHandler authenticationSuccessHandler() {
		return new CustomLoginSuccessHandler();
	}
	
	// PersistentTokenRepository 구현 클래스 객체 생성
	private PersistentTokenRepository createJDBCRepository() {
		JdbcTokenRepositoryImpl repo = new JdbcTokenRepositoryImpl();
		repo.setDataSource(datasource);
		return repo;
	}
	
//	@Bean
//	public UserDetailsService users() {
//		UserDetails user = User.builder()
//			.username("member")
//			.password("{noop}1234")
//			.roles("MEMBER")
//			.build();
//		UserDetails admin = User.builder()
//			.username("admin")
//			.password("{noop}1234")
//			.roles("ADMIN")
//			.build();
//		return new InMemoryUserDetailsManager(user, admin);
//	}
}

 

datasource가 AuthenticationConfig.java에도 있었지만, 서로 충돌하지 않는 듯 하다.

반응형

댓글()

13. 스프링 시큐리티 표현식

책의 13. 스프링 시큐리티 표현식 의 내용

타임리프에 대한 내용이라 자바 파일을 손볼 것은 없고 maven 라이브러리만 수정하면 될 듯 하다.

pom.xml

<!-- Thymeleaf에 Spring Security 적용을 위한 라이브러리 -->
<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity6</artifactId>
</dependency>

책에서는 스프링 시큐리티 5 버전을 사용해서 thymeleaf-extras-springsecurity5를 사용했지만, 나는 버전 6을 기준으로 수정하고 있기 때문에 thymeleaf-extras-springsecurity6으로 수정했다.

반응형

댓글()

12. UserDetailsService 재정의

책의 12. UserDetailsService 재정의 의 내용

SecurityConfig.java

10. JDBC 이용한 인증/인가 처리 와 같음

 

AuthenticationConfig.java

package com.mysite.config;

import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import com.mysite.common.security.CustomUserDetailsService;

@Configuration
public class AuthenticationConfig {

	@Autowired
	DataSource dataSource;

	@Autowired
	public void configGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(customUserDetailsService())
			.passwordEncoder(passwordEncoder());
	}

	//  스프링 시큐리티에서 제공되는 BCryptPasswordEncoder 클래스를 빈으로 등록한다.
	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}
	
	// 스프링 시큐리티의 UserDetailsService를 구현한 클래스를 빈으로 등록한
	@Bean
	public UserDetailsService customUserDetailsService() {
		return new CustomUserDetailsService();
	}

}
반응형

댓글()

11. 사용자 테이블 이용한 인증/인가 처리

책의 11. 사용자 테이블 이용한 인증/인가 처리

SecurityConfig.java

10. JDBC 이용한 인증/인가 처리 와 같음

 

AuthenticationConfig.java

package com.mysite.config;

import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class AuthenticationConfig {

	@Autowired
	DataSource dataSource;

	@Autowired
	public void configGlobal(AuthenticationManagerBuilder auth) throws Exception {
		String query1 = "SELECT user_id, user_pw, enabled FROM member WHERE user_id=?";
		String query2 = "SELECT b.user_id, a.auth FROM member_auth a, member b WHERE a.user_no=b.user_no AND b.user_id=?";

		auth.jdbcAuthentication()
				// 데이터 소스를 지정한다.
				.dataSource(dataSource)
				// 작성한 쿼리를 지정한다.
				.usersByUsernameQuery(query1)
				.authoritiesByUsernameQuery(query2)
				// BCryptPasswordEncoder 비밀번호 암호화 처리기를 지정한다.
				.passwordEncoder(passwordEncoder());
	}

	//  스프링 시큐리티에서 제공되는 BCryptPasswordEncoder 클래스를 빈으로 등록한다.
	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

}
반응형

댓글()

10. JDBC 이용한 인증/인가 처리

책의 10. JDBC 이용한 인증/인가 처리

SecurityConfig.java

package com.mysite.config;

import java.io.IOException;
import java.nio.file.AccessDeniedException;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.WebSecurityConfiguration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.DigestAuthenticationFilter;
import com.mysite.common.security.CustomAccessDeniedHandler;
import com.mysite.common.security.CustomLoginSuccessHandler;
import com.mysite.common.security.CustomNoOpPasswordEncoder;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;

@Configuration
@Slf4j
public class SecurityConfig {
	
	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		log.info("security config...");
		
		//URI 패턴으로 접근 제한을 설정한다.
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/board/list")
				.permitAll());
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/board/register")
				.hasRole("MEMBER"));
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/notice/list")
				.permitAll());
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/notice/register")
				.hasRole("ADMIN"));
		
		//사용자가 직접 정의한 로그인 페이지의 URI를 지정한다.
		http.formLogin()
			.loginPage("/login")
			.permitAll()
			.successHandler(authenticationSuccessHandler());
		
		//접근 거부 처리자의 URI 지정
		http.authorizeHttpRequests((authorize) -> authorize
				// Allow access to the "/accessError" page
				.requestMatchers("/accessError").permitAll() 
	            .anyRequest().authenticated()
	        )
	        .exceptionHandling((except) -> except
	            .accessDeniedHandler(accessDeniedHandler())
	        );
		//로그아웃 처리를 위한 URI를 지정하고, 로그아웃 후에 세션을 무효화한다.
		http.logout().logoutUrl("/logout").invalidateHttpSession(true);
		
		return http.build();
		
	}
	

	@Bean
	public AccessDeniedHandler accessDeniedHandler() {
		return new CustomAccessDeniedHandler();
	}
	
	@Bean
	public AuthenticationSuccessHandler authenticationSuccessHandler() {
		return new CustomLoginSuccessHandler();
	}
	
//	@Bean
//	public UserDetailsService users() {
//		UserDetails user = User.builder()
//			.username("member")
//			.password("{noop}1234")
//			.roles("MEMBER")
//			.build();
//		UserDetails admin = User.builder()
//			.username("admin")
//			.password("{noop}1234")
//			.roles("ADMIN")
//			.build();
//		return new InMemoryUserDetailsManager(user, admin);
//	}
}

AuthenticationConfig.java

package com.mysite.config;

import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.crypto.password.PasswordEncoder;
import com.mysite.common.security.CustomNoOpPasswordEncoder;

@Configuration
public class AuthenticationConfig {

	@Autowired
	DataSource dataSource;

	@Autowired
	public void configGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth.jdbcAuthentication()
				// 데이터 소스를 지정한다.
				.dataSource(dataSource)
				// 사용자가 정의한 비밀번호 암호화 처리기를 지정한다.
				.passwordEncoder(passwordEncoder());
	}

	// 사용자가 정의한 비밀번호 암호화 처리기를 빈으로 등록한다.
	@Bean
	public PasswordEncoder passwordEncoder() {
		return new CustomNoOpPasswordEncoder();
	}

}

위처럼 나눠서 실행 중에 "Error creating bean with name 'authenticationConfig': Requested bean is currently in creation: Is there an unresolvable circular reference?" 에러가 발생했다. 많은 사이트를 찾아봤지만 크게 도움이 되는 건 없었고, 

application.properties에 spring.main.allow-circular-references=true 을 추가하는 것으로 해결했다. 근데 본질적인 해결책이 아니다. 본질적으로는 디자인을 잘 해야 한다는 말을 찾았는데... 도저히 모르겠다. 

 

혹시 순환참조 문제를 해결하신 분은 댓글 달아 주시면 감사하겠습니다.ㅎㅎ

 

반응형

댓글()

9. 로그아웃 처리

책의 9. 로그아웃 처리의 설명

SecurityConfig.java

package com.mysite.config;

import java.io.IOException;
import java.nio.file.AccessDeniedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
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.WebSecurityConfiguration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.DigestAuthenticationFilter;
import com.mysite.common.security.CustomAccessDeniedHandler;
import com.mysite.common.security.CustomLoginSuccessHandler;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;

@Configuration
@EnableWebSecurity
@Slf4j
public class SecurityConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		log.info("security config...");
		
		//URI 패턴으로 접근 제한을 설정한다.
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/board/list")
				.permitAll());
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/board/register")
				.hasRole("MEMBER"));
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/notice/list")
				.permitAll());
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/notice/register")
				.hasRole("ADMIN"));
		
		//사용자가 직접 정의한 로그인 페이지의 URI를 지정한다.
		http.formLogin()
			.loginPage("/login")
			.permitAll()
			.successHandler(authenticationSuccessHandler());
		
		//접근 거부 처리자의 URI 지정
		http.authorizeHttpRequests((authorize) -> authorize
				// Allow access to the "/accessError" page
				.requestMatchers("/accessError").permitAll() 
	            .anyRequest().authenticated()
	        )
	        .exceptionHandling((except) -> except
	            .accessDeniedHandler(accessDeniedHandler())
	        );
		//로그아웃 처리를 위한 URI를 지정하고, 로그아웃 후에 세션을 무효화한다.
		http.logout().logoutUrl("/logout").invalidateHttpSession(true);
		
		return http.build();
		
	}
	
	@Bean
	public AccessDeniedHandler accessDeniedHandler() {
		return new CustomAccessDeniedHandler();
	}
	
	@Bean
	public AuthenticationSuccessHandler authenticationSuccessHandler() {
		return new CustomLoginSuccessHandler();
	}
	
	@Bean
	public UserDetailsService users() {
		UserDetails user = User.builder()
			.username("member")
			.password("{noop}1234")
			.roles("MEMBER")
			.build();
		UserDetails admin = User.builder()
			.username("admin")
			.password("{noop}1234")
			.roles("ADMIN")
			.build();
		return new InMemoryUserDetailsManager(user, admin);
	}
}
반응형

댓글()

8. 로그인 성공 처리

책의 8. 로그인 성공 처리의 설명

SecurityConfig.java

package com.mysite.config;

import java.io.IOException;
import java.nio.file.AccessDeniedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
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.WebSecurityConfiguration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.DigestAuthenticationFilter;
import com.mysite.common.security.CustomAccessDeniedHandler;
import com.mysite.common.security.CustomLoginSuccessHandler;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;

@Configuration
@EnableWebSecurity
@Slf4j
public class SecurityConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		log.info("security config...");
		
		//URI 패턴으로 접근 제한을 설정한다.
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/board/list")
				.permitAll());
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/board/register")
				.hasRole("MEMBER"));
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/notice/list")
				.permitAll());
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/notice/register")
				.hasRole("ADMIN"));
		
		//사용자가 직접 정의한 로그인 페이지의 URI를 지정한다.
		http.formLogin()
			.loginPage("/login")
			.permitAll()
			.successHandler(authenticationSuccessHandler());
		
		//접근 거부 처리자의 URI 지정
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/accessError").permitAll() // Allow access to the "/accessError" page
	            .anyRequest().authenticated()
	        )
	        .exceptionHandling((except) -> except
	            .accessDeniedHandler(accessDeniedHandler())
	        );
		
		return http.build();
		
	}
	
	@Bean
	public AccessDeniedHandler accessDeniedHandler() {
		return new CustomAccessDeniedHandler();
	}
	
	@Bean
	public AuthenticationSuccessHandler authenticationSuccessHandler() {
		return new CustomLoginSuccessHandler();
	}
	
	@Bean
	public UserDetailsService users() {
		UserDetails user = User.builder()
			.username("member")
			.password("{noop}1234")
			.roles("MEMBER")
			.build();
		UserDetails admin = User.builder()
			.username("admin")
			.password("{noop}1234")
			.roles("ADMIN")
			.build();
		return new InMemoryUserDetailsManager(user, admin);
	}
}

CustomLoginSuccessHandler.java

package com.mysite.common.security;

import java.io.IOException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;


@Slf4j
public class CustomLoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
		@Override
		public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
				Authentication auth) throws ServletException, IOException {
			log.info("onAuthenticationSuccess");
			User customUser = (User)auth.getPrincipal();
			
			log.info("username = " + customUser.getUsername());
			super.onAuthenticationSuccess(request, response, auth);
			
		}
		
}
반응형

댓글()

7. 사용자 정의 로그인 페이지

책의 7. 사용자 정의 로그인 페이지의 설명

SecurityConfig.java

@Configuration
@EnableWebSecurity
@Slf4j
public class SecurityConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		log.info("security config...");
		
		//URI 패턴으로 접근 제한을 설정한다.
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/board/list")
				.permitAll());
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/board/register")
				.hasRole("MEMBER"));
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/notice/list")
				.permitAll());
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/notice/register")
				.hasRole("ADMIN"));
		
		//사용자가 직접 정의한 로그인 페이지의 URI를 지정한다.
		http.formLogin()
			.loginPage("/login")
			.permitAll();
		
		//접근 거부 처리자의 URI 지정
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/accessError").permitAll() // Allow access to the "/accessError" page
	            .anyRequest().authenticated()
	        )
	        .exceptionHandling((except) -> except
	            .accessDeniedHandler(accessDeniedHandler())
	        );
		
		return http.build();
		
	}
	
	@Bean
	public AccessDeniedHandler accessDeniedHandler() {
		return new CustomAccessDeniedHandler();
	}
	
	@Bean
	public UserDetailsService users() {
		UserDetails user = User.builder()
			.username("member")
			.password("{noop}1234")
			.roles("MEMBER")
			.build();
		UserDetails admin = User.builder()
			.username("admin")
			.password("{noop}1234")
			.roles("ADMIN")
			.build();
		return new InMemoryUserDetailsManager(user, admin);
	}
}

LoginController.java

LoginFrom.html

책 내용 참고

반응형

'스프링 시큐리티 > 책 내용 정리' 카테고리의 다른 글

9. 로그아웃 처리  (0) 2023.05.20
8. 로그인 성공 처리  (0) 2023.05.19
6. 사용자 정의 접근 거부 처리자  (0) 2023.04.30
5. 접근 거부 처리  (0) 2023.04.22
4. 로그인 처리  (0) 2023.04.16

댓글()

6. 사용자 정의 접근 거부 처리자

책의 6. 사용자 정의 접근 거부 처리자의 내용

SecurityConfig.java

@Configuration
@EnableWebSecurity
@Slf4j
public class SecurityConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		log.info("security config...");
		
		//URI 패턴으로 접근 제한을 설정한다.
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/board/list")
				.permitAll());
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/board/register")
				.hasRole("MEMBER"));
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/notice/list")
				.permitAll());
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/notice/register")
				.hasRole("ADMIN"));
		
		http.formLogin();
		
		//접근 거부 처리자의 URI 지정
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/accessError").permitAll() // Allow access to the "/accessError" page
	            .anyRequest().authenticated()
	        )
	        .exceptionHandling((except) -> except
	            .accessDeniedHandler(accessDeniedHandler())
	        );
		
		return http.build();
		
	}
	
	@Bean
	public AccessDeniedHandler accessDeniedHandler() {
		return new CustomAccessDeniedHandler();
	}
	
	@Bean
	public UserDetailsService users() {
		UserDetails user = User.builder()
			.username("member")
			.password("{noop}1234")
			.roles("MEMBER")
			.build();
		UserDetails admin = User.builder()
			.username("admin")
			.password("{noop}1234")
			.roles("ADMIN")
			.build();
		return new InMemoryUserDetailsManager(user, admin);
	}
}

 

CustomAccessDeniedHandler.java

@Slf4j
public class CustomAccessDeniedHandler implements AccessDeniedHandler {

	@Override
	public void handle(HttpServletRequest request, HttpServletResponse response,
			AccessDeniedException accessDeniedException) throws IOException, ServletException {
		// TODO Auto-generated method stub
		log.info("handle");
		response.sendRedirect("/accessError");

	}

}
반응형

'스프링 시큐리티 > 책 내용 정리' 카테고리의 다른 글

8. 로그인 성공 처리  (0) 2023.05.19
7. 사용자 정의 로그인 페이지  (0) 2023.04.30
5. 접근 거부 처리  (0) 2023.04.22
4. 로그인 처리  (0) 2023.04.16
3. 접근 제한 설정  (0) 2023.04.16

댓글()

5. 접근 거부 처리

책의 5. 접근 거부 처리의 내용

SecurityConfig.java

@Configuration
@EnableWebSecurity
@Slf4j
public class SecurityConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		log.info("security config...");
		
		//URI 패턴으로 접근 제한을 설정한다.
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/board/list")
				.permitAll());
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/board/register")
				.hasRole("MEMBER"));
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/notice/list")
				.permitAll());
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/notice/register")
				.hasRole("ADMIN"));
		
		http.formLogin();
		
		//접근 거부 처리자의 URI 지정
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/accessError").permitAll() // Allow access to the "/accessError" page
	            .anyRequest().authenticated()
	        )
	        .exceptionHandling((except) -> except
	            .accessDeniedPage("/accessError")
	        );
		
		return http.build();
		
	}
	
	@Bean
	public UserDetailsService users() {
		UserDetails user = User.builder()
			.username("member")
			.password("{noop}1234")
			.roles("MEMBER")
			.build();
		UserDetails admin = User.builder()
			.username("admin")
			.password("{noop}1234")
			.roles("ADMIN")
			.build();
		return new InMemoryUserDetailsManager(user, admin);
	}
}
반응형

댓글()

4. 로그인 처리

책의 4. 로그인 처리 설정의 내용

SecurityConfig.java

@Configuration
@EnableWebSecurity
@Slf4j
public class SecurityConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		log.info("security config...");
		
		//URI 패턴으로 접근 제한을 설정한다.
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/board/list")
				.permitAll());
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/board/register")
				.hasRole("MEMBER"));
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/notice/list")
				.permitAll());
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/notice/register")
				.hasRole("ADMIN"));
		
		http.formLogin();
		
		return http.build();
		
	}
	
	@Bean
	public UserDetailsService users() {
		UserDetails user = User.builder()
			.username("member")
			.password("{noop}1234")
			.roles("MEMBER")
			.build();
		UserDetails admin = User.builder()
			.username("admin")
			.password("{noop}1234")
			.roles("ADMIN")
			.build();
		return new InMemoryUserDetailsManager(user, admin);
	}
}
반응형

'스프링 시큐리티 > 책 내용 정리' 카테고리의 다른 글

6. 사용자 정의 접근 거부 처리자  (0) 2023.04.30
5. 접근 거부 처리  (0) 2023.04.22
3. 접근 제한 설정  (0) 2023.04.16
2. 스프링 시큐리티 설정  (0) 2023.04.16
1. 책 내용 정리  (0) 2023.04.16

댓글()

3. 접근 제한 설정

책의 3. 접근 제한 설정의 내용

SecurityConfig.java

<@Configuration
@EnableWebSecurity
@Slf4j
public class SecurityConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		log.info("security config...");
		
		//URI 패턴으로 접근 제한을 설정한다.
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/board/list")
				.permitAll());
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/board/register")
				.hasRole("MEMBER"));
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/notice/list")
				.permitAll());
		http.authorizeHttpRequests((authorize) -> authorize
				.requestMatchers("/notice/register")
				.hasRole("ADMIN"));
		
		http.formLogin();
		
		return http.build();
		
	}
}
반응형

'스프링 시큐리티 > 책 내용 정리' 카테고리의 다른 글

6. 사용자 정의 접근 거부 처리자  (0) 2023.04.30
5. 접근 거부 처리  (0) 2023.04.22
4. 로그인 처리  (0) 2023.04.16
2. 스프링 시큐리티 설정  (0) 2023.04.16
1. 책 내용 정리  (0) 2023.04.16

댓글()

2. 스프링 시큐리티 설정

책의 2. 스프링 시큐리티 설정의 내용

SecurityConfig.java

@Configuration
@EnableWebSecurity
@Slf4j
public class SecurityConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		log.info("security config...");
		http.formLogin();
		return http.build();
		
	}
}
반응형

'스프링 시큐리티 > 책 내용 정리' 카테고리의 다른 글

6. 사용자 정의 접근 거부 처리자  (0) 2023.04.30
5. 접근 거부 처리  (0) 2023.04.22
4. 로그인 처리  (0) 2023.04.16
3. 접근 제한 설정  (0) 2023.04.16
1. 책 내용 정리  (0) 2023.04.16

댓글()

1. 책 내용 정리

실전 스프링 부트 REST API 개발 JPA + MYSQL 개정판 의 스프링 시큐리티의 내용이 deprecated 된 상태라 재작성함.

 

공부중에 스프링 시큐리티 부분이 최신 버전과 맞지 않아 최신 버전에 맞게 재작성한 부분을 블로그에 공개하려 합니다.

주로 SecurityConfig 및 관련된 설정 파일만을 수정해서 올릴 생각이며, 다른 코드 부분은 아래의 책을 통해 확인바랍니다.(확인해서 수정하지 않아도 되는 부분들은 굳이 블로그에 적지 않으려고 합니다.)

 

https://ebook-product.kyobobook.co.kr/dig/epd/ebook/E000003560021

 

실전 스프링 부트 REST API 개발 JPA + MySQL 개정판 | 향단코드 | 온노트- 교보ebook

오리지널판을 가지고 있다면 개정판을 다시 구매할 필요가 없으며 업데이트해서 사용하면 됩니다. 이 책은 스프링 부트를 이용하여 REST API 시스템을 개발하고자 하는 사람을 위한 것입니다. 이

ebook-product.kyobobook.co.kr

 - 아마 스프링 시큐리티 6.0.2 기준이 될 것임

반응형

'스프링 시큐리티 > 책 내용 정리' 카테고리의 다른 글

6. 사용자 정의 접근 거부 처리자  (0) 2023.04.30
5. 접근 거부 처리  (0) 2023.04.22
4. 로그인 처리  (0) 2023.04.16
3. 접근 제한 설정  (0) 2023.04.16
2. 스프링 시큐리티 설정  (0) 2023.04.16

댓글()