Spring Security는 사용자 정의가 가능한 인증 및 액세스 제어 프레임워크이다.
Spring Security를 이용하여 쇼핑몰의 기본인 회원을 관리하기 위한 로그인 / 로그아웃 / 회원가입을 구현하도록 한다
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
server.port=8080
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=0517
spring.datasource.url=jdbc:mysql://localhost:3306/shop
# create, update, none, create-drop, validate,
spring.jpa.hibernate.ddl-auto=update
## Jpa Properties
spring.jpa.properties.hibernate.show_sql=false
spring.jpa.properties.hibernate.format_sql=true
## Logging Level
logging.level.org.hibernate.type.descriptor.sql=debug
spring.security.user.name=root
spring.security.user.password=root
spring.security.user.roles=ADMIN
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public BCryptPasswordEncoder encoder() {
// DB 패스워드 암호화
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// super.configure(http); // 이 코드 삭제하면 기존 시큐리티가 가진 모든 기능 비활성화
http.csrf().disable(); // csrf 토큰 비활성화 코드
http.authorizeRequests()
//.antMatchers("/main", "/item/**").authenticated() // 이 주소로 시작되면 인증이 필요
.anyRequest().permitAll() // 그게 아닌 모든 주소는 인증 필요 없음
.and()
.formLogin()
.loginPage("/signin") // 인증필요한 주소로 접속하면 이 주소로 이동시킴
.loginProcessingUrl("/signin") // 스프링 시큐리티가 로그인 자동 진행 POST방식으로 로그인 진행
.defaultSuccessUrl("/main"); // 로그인이 정상적이면 "/" 로 이동
}
}
WebSecurityConfigurerAdapter 를 상속받아 그 안에 있는 메소드를 사용할수 있도록 한다.
@Bean Annotation 은 Spring 에서 이 메소드를 Bean으로 등록하는 메소드이다.
!!! 주의 !!!
반드시 class 설계시 @Configuration Annotaion을 명시하여 Bean을 사용한다 설계해야 함.
HttpSecurity를 사용하기 위해 configure 메소드 override
.antMatchers()
- 로그인이 필요한 url을 정의
.formLogin()
- 로그인 페이지와 로그인 성공 시 보내줄 url을 정의
@Data
public class PrincipalDetails implements UserDetails {
private static final long serialVersionUID = 1L;
private User user;
public PrincipalDetails(User user) {
this.user = user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> collector = new ArrayList<>();
collector.add(() -> { return user.getRole();}); // 람다식
return collector;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
Security 태그에서도 사용하고 컨트롤러에서도 자동으로 전달해주는 객체
로그인을 하게되면 로그인 객체 ( User ) 를 저장하는 역할
@RequiredArgsConstructor
@Service
public class PrincipalDetailsService implements UserDetailsService {
private final UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User userEntity = userRepository.findByUsername(username);
if(userEntity == null) {
return null;
} else {
return new PrincipalDetails(userEntity);
}
}
}
@RequiredArgsConstructor
@Service
public class AuthService {
private final UserRepository userRepository;
private final CartService cartService;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
@Transactional // Write(Insert, Update, Delete)
public User signup(User user) {
String rawPassword = user.getPassword();
String encPassword = bCryptPasswordEncoder.encode(rawPassword);
user.setPassword(encPassword);
user.setRole("ROLE_USER"); // 기본 user 권한
User userEntity = userRepository.save(user);
return userEntity;
}
@Transactional // Write(Insert, Update, Delete)
public User userUpdate(User user) {
User userEntity = userRepository.save(user);
return userEntity;
}
}
@RequiredArgsConstructor
@Controller
public class AuthController {
private final AuthService authService;
@GetMapping("/signin")
public String SigninForm() {
return "signin";
}
@GetMapping("/signup")
public String SignupForm() {
return "signup";
}
@PostMapping("/signup")
public String signup(SignupDto signupDto) {
// User에 signupDto 넣음
User user = signupDto.toEntity();
User userEntity = authService.signup(user);
return "signin"; //
}
}
구현을 완료했다면, 프론트 엔드를 설계하여 실제 화면에 띄우도록 한다.
다음과 같이 Spring Security를 이용하여 Spring boot 쇼핑몰에 회원가입 및 로그인을 구현하였다.
이제 구현한 로그인을 이용하여 쇼핑몰의 회원별로 다른 서비스를 적용해 보도록 하겠다!!!
아직.. 회원가입, 로그인시 예외처리는 하지 못하였지만 추후에 다시 업데이트 할 예정입니다.......................