의존성 주입
implementation 'org.springframework.boot:spring-boot-starter-security'
SecurityConfig 작성
@Configuration
@EnableWebSecurity // Spring Security 설정할 클래스라고 정의, 설정은 WebSebSecurityConfigurerAdapter 클래스를 상속받아 메서드를 구현하는 것이 일반적인 방법
@AllArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter{
private UserLoginService userLoginService;
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
public void configure(WebSecurity web) throws Exception {
// static 디렉터리의 하위 파일 목록은 인증 무시
web.ignoring().antMatchers("/css/**", "/js/**", "/img/**", "/lib/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// HttpSecurity를 통해 HTTP 요청에 대한 웹 기반 보안을 구성할 수 있습니다
http.headers().frameOptions().disable();
http.csrf().disable()
.authorizeRequests() //HttpServletRequest에 따라 접근(access)을 제한
// 미인증 접근 허용
.antMatchers("/login").anonymous()
// 인증 접근 허용
.antMatchers("/main/**").authenticated()
.antMatchers("/user/**").hasAnyRole("USER") // USER 권한 접근
.antMatchers("/admin/**").hasAnyRole("ADMIN") // ADMIN 권한 접근
.antMatchers("/rest/**").authenticated()
.and()
// 로그인 설정
.formLogin() // form 기반으로 인증. 로그인 정보는 기본적으로 HttpSession을 이용
.loginPage("/login").permitAll() // 로그인 페이지는 모든 사용자 접근 가능
.loginProcessingUrl("/loginProcess")
.usernameParameter("username")
.passwordParameter("password")
.permitAll()
.successHandler(loginSuccessHandler) // 로그인 성공시 핸들러
.failureHandler(loginFailureHandler) // 로그인 실패시 핸들러
// .failureForwardUrl("/login")
.and()
.logout()
.logoutUrl("/logout") // logout url 설정, 화면에서 해당 url 호출시 자동 로그아웃된다(컨트롤러 구현필요 없음)
.invalidateHttpSession(true) // HTTP 세션 초기화 여부
;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// Spring Security에서 모든 인증은 AuthenticationManager를 통해 이루어지며 AuthenticationManager를 생성하기 위해서는 AuthenticationManagerBuilder를 사용
// 로그인 처리 즉, 인증을 위해서는 UserDetailService를 통해서 필요한 정보들을 가져오는데, 예제에서는 서비스 클래스(userLoginService)에서 이를 처리
auth.userDetailsService(userLoginService).passwordEncoder(passwordEncoder());
}
}
MemberService
@RequiredArgsConstructor
@Service
public class MemberService implements UserDetailsService {
private final MemberRepository memberRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Member findMember = memberRepository.findMemberByName(username)
.orElseThrow(() -> new UsernameNotFoundException(username));
return new MemberAdaptor(findMember);
}
}
LoginSuccessHandler
@Configuration
public class LoginSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
if(authentication.isAuthenticated() && authentication.getPrincipal() instanceof MemberAdaptor){
MemberAdaptor principal = (MemberAdaptor) authentication.getPrincipal();
List<MemberRole> roles = principal.getMember().getRoles();
if(roles.stream().anyMatch(r -> r.getRoles().equals(MemberRoleEnum.ADMIN))){
response.sendRedirect("/admin/mainPage");
}else if(roles.stream().anyMatch(r -> r.getRoles().equals(MemberRoleEnum.USER))){
response.sendRedirect("/user/mainPage");
}
}else{
response.sendRedirect("/login");
}
}
}
LoginFailureHandler
@Slf4j
@Configuration
public class LoginFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
String errorMsg = "";
if(exception instanceof UsernameNotFoundException){
errorMsg = "존재하지 않는 아이디입니다.";
}else if(exception instanceof BadCredentialsException){
errorMsg = "아이디 또는 비밀번호가 잘못 입력 되었습니다.";
}
if(!StringUtils.isEmpty(errorMsg)){
request.setAttribute("errorMsg", errorMsg);
}
response.sendRedirect("/login?errorMsg=" + URLEncoder.encode(errorMsg, "UTF-8")); // redirect 처리
// request.getRequestDispatcher("/login").forward(request, response); // forward 처리
}
}
로그인 객체 반환
private MemberAdaptor getLoginMemberInfo() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(authentication.isAuthenticated() && authentication.getPrincipal() instanceof MemberAdaptor){
return (MemberAdaptor) authentication.getPrincipal();
}else{
return null;
}
}
'SpringFramework > Spring' 카테고리의 다른 글
Swagger2 설정 및 사용 (0) | 2020.11.13 |
---|---|
class 파일내 DataSource 설정 (0) | 2020.11.11 |
REST API (0) | 2020.06.10 |
Spring Security 세션정보 조회 (0) | 2020.06.09 |
Spring Boot (0) | 2020.06.09 |