Security
This commit is contained in:
@@ -0,0 +1,18 @@
|
|||||||
|
package com.security.basic.configure;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class WebMvcConfigure implements WebMvcConfigurer {
|
||||||
|
|
||||||
|
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
|
||||||
|
"classpath:/static/", "classpath:/public/", "classpath:/", "classpath:/resources/", "classpath:/META-INF/resources/", "classpath:/META-INF/resources/webjars/"
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||||
|
registry.addResourceHandler("/**").addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.security.basic.security;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class CustomAuthFailureHandler implements AuthenticationFailureHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
|
||||||
|
log.info("exception : " + exception.getMessage());
|
||||||
|
response.sendRedirect("/login");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.security.basic.security;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class CustomAuthSuccessHandler implements AuthenticationSuccessHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
|
||||||
|
log.info("authentication : " + authentication.getName());
|
||||||
|
response.sendRedirect("/home"); //인증이 성공한 후에는 home으로 이동
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package com.security.basic.security;
|
||||||
|
|
||||||
|
import com.security.basic.persistence.dao.UserRepository;
|
||||||
|
import com.security.basic.persistence.model.Privilege;
|
||||||
|
import com.security.basic.persistence.model.Role;
|
||||||
|
import com.security.basic.persistence.model.User;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CustomUserDetailsService implements UserDetailsService {
|
||||||
|
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
|
||||||
|
final User user = userRepository.findByEmail(email);
|
||||||
|
if (user == null) {
|
||||||
|
throw new UsernameNotFoundException("User Not Found");
|
||||||
|
}
|
||||||
|
return new org.springframework.security.core.userdetails.User(user.getEmail(), user.getPassword(), getAuthorities(user.getRoles()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<? extends GrantedAuthority> getAuthorities(final Collection<Role> roles) {
|
||||||
|
return getGrantedAuthorities(getPrivileges(roles));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getPrivileges(final Collection<Role> roles) {
|
||||||
|
final List<String> privileges = new ArrayList<>();
|
||||||
|
final List<Privilege> collection = new ArrayList<>();
|
||||||
|
for (final Role role : roles) {
|
||||||
|
privileges.add(role.getName());
|
||||||
|
collection.addAll(role.getPrivileges());
|
||||||
|
}
|
||||||
|
for (final Privilege item : collection) {
|
||||||
|
privileges.add(item.getName());
|
||||||
|
}
|
||||||
|
return privileges;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<GrantedAuthority> getGrantedAuthorities(final List<String> privileges) {
|
||||||
|
final List<GrantedAuthority> authorities = new ArrayList<>();
|
||||||
|
for (final String privilege : privileges) {
|
||||||
|
authorities.add(new SimpleGrantedAuthority(privilege));
|
||||||
|
}
|
||||||
|
return authorities;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.security.basic.security;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||||
|
|
||||||
|
//securedEnabled @Secured 어노테이션을 사용하여 인가를 처리하고 싶을 때 사용하는 옵션
|
||||||
|
//prePostEnabled @PreAuthorize, @PostAuthorize 어노테이션을 사용하여 인가를 처리하고 싶을 때 사용하는 옵션
|
||||||
|
//jsr250Enabled @RolesAllowed 어노테이션을 사용하여 인가를 처리하고 싶을 때 사용하는 옵션
|
||||||
|
@Configuration
|
||||||
|
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, jsr250Enabled = true)
|
||||||
|
public class MethodSecurity {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package com.security.basic.security;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
|
||||||
|
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
|
||||||
|
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.config.annotation.web.configuration.WebSecurityCustomizer;
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||||
|
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||||
|
import org.springframework.security.web.session.HttpSessionEventPublisher;
|
||||||
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Configuration
|
||||||
|
public class WebSecurityConfigure {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public WebSecurityCustomizer webSecurityCustomizer() {
|
||||||
|
return (web -> web.ignoring().requestMatchers(PathRequest.toStaticResources().atCommonLocations()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public BCryptPasswordEncoder passwordEncoder() {
|
||||||
|
return new BCryptPasswordEncoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
|
http
|
||||||
|
.csrf().disable();
|
||||||
|
|
||||||
|
//요청에 대한 설정
|
||||||
|
//permitAll시 해당 url에 대한 인증 정보를 요구하지 않는다.
|
||||||
|
//authenticated시 해당 url에는 인증 정보를 요구한다.(로그인 필요)
|
||||||
|
//hasAnyRole시 해당 url에는 특정 권한 정보를 요구한다.
|
||||||
|
// http
|
||||||
|
// .authorizeRequests()
|
||||||
|
// .antMatchers("/login", "/home").permitAll()
|
||||||
|
// .antMatchers("/user").hasAnyRole("USER", "ADMIN")
|
||||||
|
// .antMatchers("/admin").hasAnyRole("ADMIN")
|
||||||
|
// .anyRequest().authenticated();
|
||||||
|
|
||||||
|
http
|
||||||
|
.authorizeHttpRequests()
|
||||||
|
.antMatchers("/**").permitAll();
|
||||||
|
|
||||||
|
|
||||||
|
//로그인폼 관련 설정
|
||||||
|
//loginPage 로그인 페이지를 설정합니다. 해당 페이지를 설정하지 않으면 Spring Security에서 구현한 디폴트 화면이 노출됩니다.
|
||||||
|
//defaultSuccessUrl 인가된 사용자일 경우 로그인 성공 후 이동할 페이지를 설정합니다.
|
||||||
|
//failureUrl 로그인 검증이 실패한 경우 이동할 페이지를 설정합니다.
|
||||||
|
//successHandler defaultSuccessUrl에서 이동할 페이지만 설정하였다면 handler를 구현하고 이를 등록하면 좀 더 세부적인 작업을 수행할 수 있습니다.
|
||||||
|
//failureHandler successHandler와 마찬가지로 handler 구현을 통해 더 세부적인 작업을 수행할 수 있습니다.
|
||||||
|
http
|
||||||
|
.formLogin()
|
||||||
|
.defaultSuccessUrl("/home")
|
||||||
|
.failureUrl("/login?error=true")
|
||||||
|
// .successHandler(successHandler())
|
||||||
|
// .failureHandler(failureHandler())
|
||||||
|
.usernameParameter("email")
|
||||||
|
.passwordParameter("password");
|
||||||
|
|
||||||
|
http
|
||||||
|
.logout()
|
||||||
|
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
|
||||||
|
.logoutSuccessUrl("/login");
|
||||||
|
|
||||||
|
//동시 세션 관련 설정
|
||||||
|
//maximumSessions 최대 허용 가능 세션 수를 설정
|
||||||
|
//maxSessionPreventsLogin 위에서 설정한 최대 허용 세션의 수가 되었을 때 추가적인 인증이(세션 생성) 있을 경우 어떻게 처리할지 설정
|
||||||
|
//true일 경우 현재 사용자 인증 실패, false인 경우 기존 세션 만료
|
||||||
|
//expiredUrl 세션이 만료된 경우 이동할 페이지를 설정정
|
||||||
|
http
|
||||||
|
.sessionManagement()
|
||||||
|
.maximumSessions(1)
|
||||||
|
.maxSessionsPreventsLogin(true)
|
||||||
|
.expiredUrl("/expired");
|
||||||
|
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public static ServletListenerRegistrationBean httpSessionEventPublisher() {
|
||||||
|
return new ServletListenerRegistrationBean(new HttpSessionEventPublisher());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public AuthenticationSuccessHandler successHandler() {
|
||||||
|
return new CustomAuthSuccessHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public AuthenticationFailureHandler failureHandler() {
|
||||||
|
return new CustomAuthFailureHandler();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user