정의
애플리케이션의 보안을 담당하는 강력한 프레임워크
인증(Authentication)과 인가(Authorization)를 통해 애플리케이션을 보호하는데 사용
인증(Authentication)
- 사용자가 누구인지 확인
- 일반적으로 사용자가 입력한 아이디와 비밀번호를 검증하여 사용자의 신원을 확인
인가(Authorization)
- 인증된 사용자가 애플리케이션에서 무엇을 할 수 있는지 결정
- 사용자에게 특정 리소스에 대한 접근 권한이 있는지 확인
주요 구성
Security Context
- 현재 인증된 사용자와 관련된 보안 정보를 저장하는 컨텍스트
- SecurityContextHolder를 통해 접근 가능
Security Filter Chain
- 여러가지 보안 필터로 구성된 체인
- HTTP 요청이 이 필터 체인을 통과하면서 검사
UserDetailsService
- 사용자 정보를 로드하는 서비스 인터페이스
- loadUserByUsername() 메서드를 사용해서 데이터베이스에서 정보 조회
PasswordEEncoder
- 비밀번호를 암호화 하는 인터페이스
AuthenticationManager
- 인증을 처리하는 주요 인터페이스
- authenticate() 메서드를 통해 사용자의 자격 증명을 검증
예제
import com.metacoding.authblog.user.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;
@Configuration
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain config(HttpSecurity http) throws Exception {
http.csrf(c->c.disable());
http.authorizeHttpRequests(r ->
r.requestMatchers("/s/**").authenticated()
.anyRequest()
.permitAll())
.formLogin(f ->f.loginPage("/login-form")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/")
.permitAll());
return http.build();
}
}
@Entity
@Table(name = "user_tb")
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class User implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(unique = true, nullable = false)
private String username;
@Column(nullable = false)
private String password;
@Column(nullable = false)
private String email;
@CreationTimestamp
private Timestamp createdAt;
@Override
public String getUsername() { //계정의 고유한 값을 리턴(중복이없는 값)
return username;
}
@Override
public String getPassword() { //계정의 비밀번호를 리턴
return password;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
@Data
public class JoinDTO {
private String username;
private String password;
private String email;
public User toEntity(PasswordEncoder passwordEncoder)
String encodedPassword = passwordEncoder.encode(password);
System.out.println(encodedPassword);
User user = new User(null, username, encodedPassword, email, null);
return user;
}
}
@Controller
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@GetMapping("/login-form")
public String loginForm() {
return "user/login-form";
}
@PostMapping("/join")
public String join(UserRequset.JoinDTO joinDTO) {
userService.회원가입(joinDTO);
return "redirect:/login-form";
}
}
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@RequiredArgsConstructor
public class UserService implements UserDetailsService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
// post 요청
// login일때 호출
// key 값 -> username, password
// content-type -> x-www-form-urlencoded
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("loadUserByUsername");
User user = userRepository.findByUsername(username);
return user;
}
@Transactional
public void 회원가입(UserRequset.JoinDTO joinDTO){
userRepository.save(joinDTO.toEntity(passwordEncoder));
}
}
@RequiredArgsConstructor
@Repository
public class UserRepository {
private final EntityManager em;
public User save(User user) {
em.persist(user);
return user;
}
}
Share article