안녕하세요 오늘은 스프링 시큐리티를 사용하여 로그인 기능을 구현해 보도록 하겠습니다
Spring Security는 Spring Boot의 하위 프레임 워크이며 Java 어플리케이션에 인증과 권한 부여를 제공하는데 중점을 둔 프레임워크입니다. Spring에서는 사실상 Spring Security를 표준으로 하여 보안기능을 제공하며 필터기반으로 처리합니다. 사용자의 ID와 PASSWORD를 입력받아 인증을 하고 역할 및 권한을 부여할 수 있으며 CSRF(Cross Stie Script Forgery) 같은 취약점에도 대응이 가능합니다.
지금부터 spring security를 사용해 로그인 기능을 구현해 보도록 하겠습니다
spring security를 사용하기 위해서는 하단 코드를 build.gradle에 넣어줘야 합니다
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
implementation 'org.springframework.boot:spring-boot-starter-security'
스프링 시큐리티를 사용하기 위해 스프링 시큐리티에 필요한bean을 추가해주는 config 클래스 파일을 추가해 줘야 합니다
@EnableWebSecurity
@EnableMethodSecurity
@Configuration
@RequiredArgsConstructor
public class SecurityConfig {
@Bean
public static BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations());
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(requests -> requests
.requestMatchers("/", "/login", "/join").permitAll()
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.defaultSuccessUrl("/", true)
.permitAll()
)
.logout(logout -> logout
.permitAll());
return http.build();
}
}
로그인 페이지에서 로그인을 할때 url호출없이 service를 이용할수 있는 로직을 spring security에서 제공해줍니다
@Service
@RequiredArgsConstructor
public class AccountService implements UserDetailsService{
private final UserMapper userMapper;
private final BCryptPasswordEncoder encoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Account account = new Account();
account.setId(username);
account = userMapper.findUser(account);
if(account != null){
List<GrantedAuthority> authorities = new ArrayList();
return new User(account.getId(), account.getPasswd(), authorities);
}
return null;
}
@Transactional
public boolean join(String userId, String userPwd) {
Account checkUser = new Account();
checkUser.setId(userId);
if (userMapper.findUser(checkUser) != null){
return false;
}
Account newUser = new Account();
newUser.setId(userId);
newUser.setPasswd(encoder.encode(userPwd));
userMapper.save(newUser);
return true;
}
}
UserDetailsService 인터페이스를 상속받아 loadUserByUsername 메서드를 오버라이딩 하여 로그인시 로그인 체크를 할수 있도록 로직을 구현하였습니다
@Getter
@Setter
public class Account implements UserDetails {
private String id;
private String passwd;
private String authority;
@Override
public String getUsername() {
return this.id;
}
...
사용자 VO에 UserDetails 인터페이스를 상속받으면 html에서 뿐아니라 백앤드단에서도 로그인되어있을때 자유롭게 로그인 체크나 로그인 데이터를 가져와서 체크를 할수 있습니다
로그인 여부를 확인하기 위해 util파일을 만들어 주었습니다
public class LoginUtil {
public static boolean isLogin(){
boolean result = true;
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if(principal instanceof String){
result = false;
}
return result;
}
}
SecurityContextHolder.getContext().getAuthentication().getPrincipal() 을 사용해 로그인 정보를 가져올수 있습니다
실행 결과 정상적으로 로그인, 회원가입기능이 구현되는것을 확인할수 있었습니다 다음번엔 더 재미있는 소재로 찾아뵙겠습니다 감사합니다.
안녕하세요! 제가 지금 스프링부트 3.1.7, 스프링시큐리티6을 사용중인데 BCryptPasswordEncoder클래스를 생성하는 코드에서 @Bean어노테이션을 다니 어노테이션은 이곳에 허용되지 않는다라고 하네요 버전이 달라서 그런거겠죠?