일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 예약
- 추후정리
- 적용우선순위
- subquery
- 서브쿼리
- EC2
- 참조키
- foreignkey
- 검색
- 메세지수정
- 테스트메소드
- 포트
- 컨테이너실행
- 테스트
- 외부키
- ㅔㄴ션
- ubuntu
- docker명령어
- WeNews
- 커밋메세지수정
- 2 > /dev/null
- MySQL
- appspec
- 네이티브쿼리
- appspec.yml
- querydsl
- Query
- AuthenticationEntryPoint
- application.yml
- 메소드명
- Today
- Total
제뉴어리의 모든것
favicon.ico 와 AuthenticationEntryPoint .. 본문
사건의 시작은 Spring Security를 적용한 상태에서 로그인할때 비밀번호가 틀렸을 경우 Exception을 발생시켜 처리를 해주려는 상황에서 발생했다..아니 이미 계속 문제가 있던 상황이였다...
비밀번호를 검증하는 부분인 AuthenticationProvider 인터페이스를 구현한 CustomAuthenticationProvider라는 클래스를 만들어주었고 이 인터페이스의 필수 override 메소드인 authenticate에서 비밀번호가 틀릴경우
본인이 직접 만든 exception 클래스를 발생시키도록 하였다. 그런데 문제는 로그인을 시도하지도 않았는데 자꾸 exception이 발생하여서 인증과정중에 exception이 발생할 경우 작동하는
AuthenticationEntryPoint 인터페이스의 commence 메소드가 작동한다는것이였다..
즉, 로그인시 에러가 발생하면 처리하려고 작업을 하였는데 그냥 index.html(웰컴페이지)만 들어가도 만든작업이 구동된다..
Spring Security의 설정을 담당하는 WebSecurityConfigurerAdapter
package org.zerock.member_board.config;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
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.WebSecurityConfigurerAdapter;
import org.zerock.member_board.service.CustomOAuth2UserService;
import org.zerock.member_board.service.MemberServiceImpl;
import org.zerock.member_board.service.util.AuthenticationExceptionHandler;
@RequiredArgsConstructor
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final CustomOAuth2UserService customOAuth2UserService;
private final MemberServiceImpl memberService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.headers().frameOptions().disable()
.and()
.authorizeRequests()
.antMatchers("/", "/replies/**","/board/list","/board/read","/css/**","/login/**",
"/vendor/**","/modal/**","/member/**","/login/**",
"/review/**","/img/**","/attend/getAttend","/websocket/**",
"/ws_sock/**","/chat/**","/html/**","/webjars/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/member/login")
.defaultSuccessUrl("/")
.and()
.exceptionHandling()
.authenticationEntryPoint(authenticationExceptionHandler()) //exception 발생시 돌아갈 핸들러 설정
.and()
.logout()
.logoutSuccessUrl("/member/login")
.and()
.oauth2Login().defaultSuccessUrl("/")
.userInfoEndpoint().userService(customOAuth2UserService)
.and();
http.sessionManagement()
.maximumSessions(1)
.expiredUrl("/member/login")
.maxSessionsPreventsLogin(false);
}
// public void configure(AuthenticationManagerBuilder auth) throws Exception { // 9
// auth.userDetailsService(memberService)
// // 해당 서비스(userService)에서는 UserDetailsService를 implements해서
// // loadUserByUsername() 구현해야함 (서비스 참고)
// .passwordEncoder(new BCryptPasswordEncoder());
// }
@Bean
public AuthenticationExceptionHandler authenticationExceptionHandler(){
AuthenticationExceptionHandler authenticationExceptionHandler = new AuthenticationExceptionHandler();
return authenticationExceptionHandler;
}
}
로그인폼에서 입력한 id와 password를 검증하는 AuthenticationProvider
package org.zerock.member_board.service.util;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.zerock.member_board.entity.Member;
import org.zerock.member_board.error.exception.ControllerException;
import org.zerock.member_board.service.MemberServiceImpl;
/**
* 인증 과정 검증 클래스
*/
@RequiredArgsConstructor
public class CustomAuthenticationProvider implements AuthenticationProvider {
private final MemberServiceImpl memberService;
@SuppressWarnings("unchecked")
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = (String) authentication.getPrincipal();
String password = (String) authentication.getCredentials();
Member member = (Member) memberService.loadUserByUsername(username);
if(!matchPassword(password, member.getPassword())) {
throw new ControllerException("not.match.password", this.getClass().getName());
// throw new BadCredentialsException(username);
}
if(!member.isEnabled()) {
throw new BadCredentialsException(username);
}
return new UsernamePasswordAuthenticationToken(username, password, member.getAuthorities());
}
@Override
public boolean supports(Class<?> authentication) {
return true;
}
private boolean matchPassword(String loginPwd, String password) {
return loginPwd.equals(password);
}
}
비밀번호가 틀릴 경우 발생시키려 만든 직접만든 ControllerException클래스
package org.zerock.member_board.error.exception;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@Getter
public class ControllerException extends RuntimeException{
private String code;
private String path;
}
인증 과정중 Exception 발생시 구동 될 콜백 메소드 commence
package org.zerock.member_board.service.util;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class AuthenticationExceptionHandler implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException {
httpServletResponse.sendRedirect("/exception/authentication");
}
}
소스는 위와 같다..
어쨋든 문제의 원인은 브라우저에서 /favicon.ico를 요청 하고 서버에서는 위에 보시다시피 antMatchers() 부분에 /favicon.ico를 permitAll로 해놓지 않았다..
그래서 계속 commence 메소드에 진입을 했던것이다..
참고로, 링크를 보면 알 수 있듯이 사이트에 접근하면 브라우저가가 자동으로 요청을 하여 favicon을 얻어와 주소창 옆에 아이콘을 띄워주는것으로 보인다.
그렇기 때문에 이러한 favicon 요청이 불필요하다면
해당 html 페이지의 <head> </head> 사이에
<link rel="icon" href="data:,"> 를 삽입해주면 된다.
그럼 브라우저가 /favicon.ico 요청을 하지 않는다.
'Spring Boot' 카테고리의 다른 글
DTO 유효성 검사시 주의 사항 (@NotBlank, @NotEmpty, @NotNull에 대하여) - 매우 중요 (0) | 2022.08.28 |
---|---|
DTO 값 검증 처리 방법 (0) | 2021.04.21 |
@Builder.Default (0) | 2021.04.09 |
ResponseEntity<>와 ajax 사용시 주의사항 (0) | 2021.04.08 |
Spring Boot Devtools 알아보기 (0) | 2021.04.07 |