AuthenticationProvider found for org.springframework.security.authentication.UsernamePasswordAuthenticationToken
당황스럽다. 로그인 시도하면 위와 같은 에러가 나면서 실패한다.
왜 일까? 서치, ChatGPT 도움을 받을려고 했으나 모두 실패다.
디버깅을 할 수 없이 하게 됐고,
Provider 쪽에서 UserService주입이 안되어 나오는 현상이였다.
아래 코드에서 수정본을 올려본다.
package com.shop.shop.config;
import com.shop.shop.service.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.ObjectPostProcessor;
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.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
@Configuration
@EnableWebSecurity(debug = true)
@RequiredArgsConstructor
public class SecurityConfig {
private final MemberService memberService;
private final ObjectPostProcessor<Object> objectPostProcessor;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
RequestMatcher requestMatcher = new AntPathRequestMatcher("/members/new");
http
.authorizeHttpRequests(auth -> auth.requestMatchers(new AntPathRequestMatcher("/css/**")).permitAll()).addFilter(getAuthenticationFilter())
.authorizeHttpRequests(authorize -> authorize
.requestMatchers(requestMatcher).permitAll()
.anyRequest()
.authenticated()
)
.formLogin(formLogin -> formLogin
.loginPage("/members/login")
.usernameParameter("email")
.passwordParameter("password")
.defaultSuccessUrl("/")
.permitAll()
.failureUrl("/members/login/error")
)
.logout(logout -> logout
.logoutRequestMatcher(new AntPathRequestMatcher("/members/logout"))
.logoutSuccessUrl("/")
);
return http.build();
}
public AuthenticationManager authenticationManager(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(memberService).passwordEncoder(new BCryptPasswordEncoder());
return auth.build();
}
private AuthenticationFilter getAuthenticationFilter() throws Exception {
AuthenticationFilter authenticationFilter = new AuthenticationFilter();
AuthenticationManagerBuilder builder = new AuthenticationManagerBuilder(objectPostProcessor);
authenticationFilter.setAuthenticationManager(authenticationManager(builder));
return authenticationFilter;
}
}
package com.shop.shop.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.shop.shop.dto.MemberFormDto;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import java.io.IOException;
import java.util.ArrayList;
public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
try {
MemberFormDto creds = new ObjectMapper().readValue(request.getInputStream(), MemberFormDto.class);
return getAuthenticationManager().authenticate(
new UsernamePasswordAuthenticationToken(
creds.getEmail(),
creds.getPassword(),
new ArrayList<>()
)
);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain,
Authentication authResult) throws IOException, ServletException {
//super.successfulAuthentication(request, response, chain, authResult);
}
}
다음과 같이 수정을 거치니 문제없이 작동하는걸 알 수 있었다.
기타 Test 코드도 첨부 하겠다.
package com.shop.shop.service;
import com.shop.shop.dto.MemberFormDto;
import com.shop.shop.entity.Member;
import jakarta.transaction.Transactional;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.MockMvc;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
@SpringBootTest
@AutoConfigureMockMvc
@Transactional
@TestPropertySource(locations = "classpath:application.yml")
class MemberServiceTest {
@Autowired
MemberService memberService;
@Autowired
PasswordEncoder passwordEncoder;
@Autowired
private MockMvc mockMvc;
public Member createMember() {
MemberFormDto memberFormDto = new MemberFormDto();
memberFormDto.setName("test");
memberFormDto.setEmail("test@gmail.com");
memberFormDto.setPassword("1234");
memberFormDto.setAddress("test address");
return Member.createMember(memberFormDto, passwordEncoder);
}
public Member createMember(String email, String password) {
MemberFormDto memberFormDto = new MemberFormDto();
memberFormDto.setName("test");
memberFormDto.setEmail(email);
memberFormDto.setPassword(password);
memberFormDto.setAddress("test address");
return Member.createMember(memberFormDto, passwordEncoder);
}
@Test
@DisplayName("회원가입 테스트")
public void saveMemberTest() {
// given
Member member = createMember();
// when
Member savedMember = memberService.saveMember(member);
// then
assertEquals(member.getName(), savedMember.getName());
assertEquals(member.getEmail(), savedMember.getEmail());
assertEquals(member.getPassword(), savedMember.getPassword());
assertEquals(member.getAddress(), savedMember.getAddress());
assertEquals(member.getRole(), savedMember.getRole());
}
@Test
@DisplayName("중복 회원 예외 테스트")
public void saveDuplicateMemberTest() {
// given
Member member1 = createMember();
Member member2 = createMember();
// when
memberService.saveMember(member1);
IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.saveMember(member2));
// then
assertEquals("이미 존재하는 회원입니다.", e.getMessage());
}
@Test
@DisplayName("로그인 성공 테스트")
public void loginSuccessTest() throws Exception {
// given
String email = "test@gmail.com";
String password = "1234";
this.createMember(email, password);
// when
mockMvc.perform(formLogin().userParameter("email")
.password("password")
.loginProcessingUrl("/members/login")
.user(email).password(password))
.andExpect(SecurityMockMvcResultMatchers.authenticated());
}
}
이상 시큐리티 삽질기를 끝맺음 해본다.
간만에 붙여보니 느낌도 오고 오래된 호기심 발동으로 저녁도 굶어가며 열정을 불태웠다.
이제는 권한 및 각 페이지를 만들어 봐야 겠다.
시간이 나면 JWT로 변경하고 RestAPI 기능도 있는 걸로 변경해 볼려고 한다.
이만 줄인다.
모두 성공하길 바란다.
숲방갤: 자연과 기술이 만나는 공간 (0) | 2024.09.05 |
---|---|
노래 - "빈칸" (0) | 2024.09.02 |
노래 - "따분한 일요일" (2) | 2024.09.01 |
아이폰 SWIFT 개발 입문 1일차 (0) | 2023.07.27 |
SpringBoot 3.0^ + JPA + QueryDSL 5.0^ + Security 설정 (0) | 2023.07.22 |
PPT 표지 디자인의 기술 마스터하기: 청중의 관심을 끌고 감동을 주고 사로잡으십시오 (0) | 2023.05.13 |
샤오미 공기청정기: 기술과 건강한 삶의 격차 해소 (0) | 2023.05.09 |
Chat GPT 사용법, 인공지능과 대화하는 새로운 경험을 느껴보세요! (0) | 2023.04.20 |
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |