SpringFramework/Spring

Spring Security 설정

lovineff 2020. 6. 9. 11:38

의존성 주입

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