dev.note/Web
[spring boot] spring security 6 로그인 서비스
CrazyK
2022. 12. 14. 17:41
TMI
나이가 들수록 영민함과 멀어지기에
이젠 기록을 해둬야 겠다
사전 Gradle 설정 사항(DB가 둘다 되는지 확인하고 싶었다)
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.h2database:h2:2.1.210'
runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
}
1. 설정 클래스에 다음의 내용을 넣어준다
@Configuration
@EnableWebSecurity
@AllArgsConstructor
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
}
2. JPA 기반이므로 domain 클래스를 작성한다
@Entity @Getter @Setter
public class Member {
@Id @GeneratedValue(strategy= GenerationType.IDENTITY)
@Column(name="idx")
private long idx;
@Column(name="identity", unique = true) // 8자로 password와 맞추고 싶었다...
private String identity;
@Column(name="password")
private String password;
@Column(name="username")
private String username;
}
3. spring security의 UserDetails를 구현하는 DTO를 만들어준다
참고로... 당연한 거지만 Entity를 DTO로 사용하려고 하지 마라
@Getter @Setter @Builder
public class MemberDTO implements UserDetails {
private long idx;
private String identity;
private String password;
private String username;
private List<AuthorityDTO> authorities;
@Override
public Collection<AuthorityDTO> getAuthorities() {
return authorities == null ? new ArrayList<>() : authorities;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
중요한건 아니지만 AuthorityDTO
@Getter @Setter
public class AuthorityDTO implements GrantedAuthority {
private long idx;
private String authority;
private String authorityName;
}
4. JPA Repository 생성
public interface MemberRepository extends JpaRepository<Member, Long> {
Optional<Member> findByIdentity(String identity);
}
5. 서비스 구현
@AllArgsConstructor
@Service
public class LoginService implements UserDetailsService {
private MemberRepository memberRepository;
@Override
public UserDetails loadUserByUsername(String identity) throws UsernameNotFoundException {
Member member = memberRepository.findByIdentity(identity)
.orElseThrow(() -> new UsernameNotFoundException(identity));
// 기왕이면 Object Mapper 를 써라. 지금은 설정이 귀찮다..
return MemberDTO.builder()
.idx(member.getIdx())
.identity(member.getIdentity())
.password(member.getPassword())
.username(member.getUsername())
.build();
}
}
6. 테스트(사전에 필요한 데이터는 넣어주고)
@SpringBootTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class LoginTest {
@Autowired
LoginService loginService;
@Autowired
private AuthenticationManager authenticationManager;
@Test
void loginTest() {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("identity", "password"));
}
}