Dev/SpringBoot

12. [springboot] Spring Boot 로그인 실패 이후 처리

VIPeveloper 2020. 6. 12. 10:39
728x90
반응형

1. 서론

- 저번 포스팅에서는 로그인 성공 이후 처리에 대해 알아보았습니다.

 

11. [springboot] 스프링부트 로그인 성공 이후 처리

1. 서론 - 로그인 처리가 성공하였을 경우 처리에 대해 공부해보겠습니다. - 일반 쇼핑몰 같은 경우, 로그인하지 않은 채 서비스들을 둘러보고 있다가, 결재하려 할 때 로그인 처리를 요구하는 경

dkyou.tistory.com

이번에는 로그인 실패시, 알림창 띄우는 방법에 대해 알아보도록 하겠습니다.

로그인 실패 시, 알람 띄우기

2. 본론

SecurityConfig.java

package com.example.springsecurity.security;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationProvider;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

@Configuration
@EnableWebSecurity
@Slf4j
@AllArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final AuthenticationSuccessHandler customSuccessHandler;

    private final AuthenticationFailureHandler customFailureHandler;

    private final AuthenticationDetailsSource authenticationDetailsSource;

    private final UserDetailsService userDetailsService;
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {

//        String password = passwordEncoder().encode("1111");
//
//        auth.inMemoryAuthentication().withUser("user").password(password).roles("USER");
//        auth.inMemoryAuthentication().withUser("manager").password(password).roles("MANAGER");
//        auth.inMemoryAuthentication().withUser("admin").password(password).roles("ADMIN");
//        auth.userDetailsService(userDetailsService);
        auth.authenticationProvider(authenticationProvider());
    }

    @Bean
    public AuthenticationProvider authenticationProvider() {
        return new CustomAuthenticationProvider();
    }

    @Override
    // js, css, image 설정은 보안 설정의 영향 밖에 있도록 만들어주는 설정.
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().requestMatchers(PathRequest.toStaticResources().atCommonLocations());
    }

    @Bean
    // BCryptPasswordEncoder는 Spring Security에서 제공하는 비밀번호 암호화 객체입니다.
    // Service에서 비밀번호를 암호화할 수 있도록 Bean으로 등록합니다.
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/","/loginUser","/login*").permitAll()
                .antMatchers("/user").hasRole("USER")
                .antMatchers("/manager").hasRole("MANAGER")
                .antMatchers("/admin").hasRole("ADMIN")
                .anyRequest().authenticated()
            .and()
                .formLogin()
                .loginPage("/login")                    // controller mapping
                .loginProcessingUrl("/login_proc")      // th:action="@{/login_proc}"
                .authenticationDetailsSource(authenticationDetailsSource)   // 추가 파라메터 설정작업시, 설정해주기
                .defaultSuccessUrl("/")
                .successHandler(customSuccessHandler)
                .failureHandler(customFailureHandler)	// 실패 핸들러
                .permitAll();
    }
}

 

- 실패 핸들러를 적용해줍니다.

 

CustomAuthenticationFailureHandler.java

package com.example.springsecurity.security;

import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {

        String msg = "Invaild Username or Password";

        if(exception instanceof BadCredentialsException){

        }else if(exception instanceof InsufficientAuthenticationException){
            msg = "Invalid Secret Key";
        }

        setDefaultFailureUrl("/login?error=true&exception="+msg);

        super.onAuthenticationFailure(request,response,exception);
    }
}

 

- 예외처리 진행해주고, 에러 메세지를 띄워줍니다.

 

loginController.java

    @GetMapping("/login")
    public String login(@RequestParam(value = "error", required = false) String error,
                        @RequestParam(value = "exception", required = false) String exception,
                        Model model)
    {
        model.addAttribute("error",error);
        model.addAttribute("exception",exception);
        return "user/login/login";
    }

에러가 있다면, model에 반영하여 넘겨준다.

login.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/header :: header"></head>
<body>
<div class="container">
    <div th:replace="fragments/bodyHeader :: bodyHeader"></div>
    <h1>로그인</h1>
    <div th:if="${param.error}">
        <p th:text="${exception}" class="alert alert-danger"></p>
    </div>
    <form th:action="@{/login_proc}" method="post">
        <input th:type="hidden" th:value="secret" name="secret_key">
        <div class="form-group">
            <label th:for="username">이메일</label>
            <input type="text" name="username" class="form-control" placeholder="이메일 입력해주세요">
        </div>
        <div class="form-group">
            <label th:for="password">비밀번호</label>
            <input type="password" class="form-control" name="password" placeholder="비밀번호">
        </div>
        <button type="submit" class="btn btn-primary">Submit</button>
    </form>
    <br/>
    <div th:replace="fragments/footer :: footer"></div>
</div>
</body>
</html>

${param.error}가 있다면, 예외처리를 출력해줍니다.

 

3. 결론

로그인 실패 시, 알람 띄우기

위에서 본 내용처럼 유저 정보가 잘못 되었을 때, 커스터마이징 된 알람을 띄울 수 있게 되었습니다.

728x90
반응형