쇼핑몰 프로젝트 할 때 세션과 로그인 기능을 사용하기 위해,
membermanage 프로젝트에서 로그인/로그아웃/회원가입 기능 을 도입하는 연습을 해보았습니다.
https://github.com/rladuswl/MemberManage
implementation 'org.springframework.boot:spring-boot-starter-security'
testImplementation 'org.springframework.security:spring-security-test'
spring.security.user.name=root
spring.security.user.password=root
spring.security.user.roles=ADMIN
package com.example.membermanage.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity // DB에 테이블 자동 생성
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(unique = true) // username 중목 안됨
private String username;
private String password;
private String name;
private String email;
private String role; // 권한
private LocalDateTime createDate; // 날짜
@PrePersist // DB에 INSERT 되기 직전에 실행. 즉 DB에 값을 넣으면 자동으로 실행됨
public void createDate() {
this.createDate = LocalDateTime.now();
}
}
package com.example.membermanage.repository;
import com.example.membermanage.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import javax.servlet.http.HttpSession;
// <Entity, Entity-id>
@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
User findByUsername(String username);
}
package com.example.membermanage.config.auth;
import com.example.membermanage.entity.User;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
import java.util.Collection;
@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;
}
}
package com.example.membermanage.config.auth;
import com.example.membermanage.entity.User;
import com.example.membermanage.repository.UserRepository;
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.stereotype.Service;
@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);
}
}
}
package com.example.membermanage.config;
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.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@EnableWebSecurity // 해당 파일로 시큐리티 활성화
@Configuration // IoC 등록
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/**").authenticated() // 이 주소로 시작되면 인증이 필요
.anyRequest().permitAll() // 그게 아닌 모든 주소는 인증 필요 없음
.and()
.formLogin()
.loginPage("/signin") // 인증필요한 주소로 접속하면 이 주소로 이동시킴
.loginProcessingUrl("/signin") // 스프링 시큐리티가 로그인 자동 진행 POST방식으로 로그인 진행
.defaultSuccessUrl("/member/list"); // 로그인이 정상적이면 "/" 로 이동
}
}
package com.example.membermanage.service;
import com.example.membermanage.entity.User;
import com.example.membermanage.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpSession;
import javax.transaction.Transactional;
@RequiredArgsConstructor
@Service
public class AuthService {
private final UserRepository userRepository;
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 userEntity = userRepository.save(user);
return userEntity;
}
}
package com.example.membermanage.controller;
import com.example.membermanage.entity.User;
import com.example.membermanage.service.AuthService;
import com.example.membermanage.web.dto.auth.SignupDto;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletRequest;
@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(User user) {
User newUser = user; //새로운 유저 받음
User userEntity = authService.signup(user);
System.out.println(userEntity);
return "signin";
}
// 로그인성공 창에서 로그아웃 버튼
//@RequestMapping(value="logout", method = RequestMethod.GET)
@GetMapping("/logout")
public String logout(HttpSession session) throws Exception {
authService.logout(session);
return "redirect:/signin";
}
}
package com.example.membermanage.web.dto.auth;
import com.example.membermanage.entity.User;
import lombok.Data;
@Data
public class SignupDto {
private String username;
private String password;
private String email;
private String name;
public User toEntity() {
return User.builder()
.username(username)
.password(password)
.email(email)
.name(name)
.build();
}
}
잘보고가요~