728x90
320x100
📌 로그인 과정 설명
- 보통 insert는 get 방식으로 처리하지만, 로그인은 중요한 정보를 처리하는 것이기 때문에 post 방식으로 처리한다.
- 우리가 처리하기보다는 Spring Security가 처리해준다 (➡️ controller를 만들지 않음)
⚡️ SecurityConfig
.formLogin(formConfig ->
formConfig.loginPage("/auth/signin") //GET
.loginProcessingUrl("/auth/signin") //POST
.defaultSuccessUrl("/"))
- Spring Security에 회원 가입을 구현할 때 구현한 .loginPage("/auth/signin") 코드 밑에 .loginProcessingUrl("/auth/signin")을 추가해준다
- 둘의 url은 같지만 위에는 get 요청이고 밑에는 post 요청이다.
⚡️ PrincipalDetailsService
package yerong.InstagramCloneCoding.config.auth;
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;
import yerong.InstagramCloneCoding.domain.user.User;
import yerong.InstagramCloneCoding.repository.UserRepository;
@Service
@RequiredArgsConstructor
public class PrincipalDetailsService implements UserDetailsService {
private final UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username).orElseThrow();
return new PrincipalDetails(user);
}
}
- UserDetailsService를 상속받는 PrincipalDetailsService 클래스를 생성해준다.
- SecurityConfig에서 로그인 요청을 낚아채면 이 클래스가 처리를 해주는 것이다.
- 우리는 username만 필요하다. username이 있는지 없는지 처리해야 함
- password는 security가 알아서 비교해준다
- UserRepository가 필요하다.
- 리턴이 잘 되면 알아서 UserDetails 타입을 세션으로 만들어준다.
- 리턴 타입이 UserDetails이기 때문에 UserDetails을 상속받는 PrincipalDetails을 생성 후 이것을 리턴해주는 것이다.
- User 을 넘기기 때문에 user 객체의 데이터를 사용 가능하다.
⚡️ PrincipalDetails
package yerong.InstagramCloneCoding.config.auth;
import lombok.Getter;
import lombok.Setter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import yerong.InstagramCloneCoding.domain.user.User;
import java.util.ArrayList;
import java.util.Collection;
@Getter
@Setter
public class PrincipalDetails implements UserDetails {
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().getKey();});
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;
}
}
✅ PrincipalDetails 알아보기
- getAuthorities() : 권한을 가져오는 함수
- 권한이 1개 이상일 수도 있음 (USER, ADMIN 등 Role)
- return 타입이 Collection<? extends GrantedAuthorites>
- getPassword() : 비밀번호를 가져오는 함수
- getUsername() : username을 가져오는 함수
- isAccountNonExpired() : 계정이 만료되었는가? (아니라면 true)
- isAccountNonLocked() : 계정이 잠겼는가? (아니라면 true)
- isCredentialNonExpired() : 비밀번호가 만료되었는가? (아니라면 true)
- isEnabled() : 계정이 비활성화 되었는가? (아니라면 true)
➡️ 이 boolean 타입들이 false라면 로그인 불가능
⭐️ 404 에러가 떴다면 로그인에 성공한 것임❗️
➡️ 그동안 권한이 필요했던 user/** 등의 url에 들어가보면 404 에러가 뜰 것임
➡️ localhost:8080/logout을 하고 다시 들어가보면 로그인 창으로 redirect 되는 것을 볼 수 있음
📌 로그인 후 화면 처리
⚡️ ImageController
package yerong.InstagramCloneCoding.web.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class ImageController {
@GetMapping({"/", "/image/story"})
public String story(){
return "views/image/story";
}
@GetMapping("/image/popular")
public String popular(){
return "views/image/popular";
}
@GetMapping("/image/upload")
public String upload(){
return "views/image/upload";
}
}
- 중괄호({})를 사용하면 여러 url을 매핑할 수 있음
⚡️ UserController
package yerong.InstagramCloneCoding.web.controller;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import yerong.InstagramCloneCoding.config.auth.PrincipalDetails;
@Controller
public class UserController {
@GetMapping("/user/{id}")
public String profile(@PathVariable("id") Long id){
return "views/user/profile";
}
@GetMapping("/user/{id}/update")
public String update(@PathVariable("id") Long id, @AuthenticationPrincipal PrincipalDetails principalDetails){
// principalDetails.getUser() 로 편리하게 세션 사용
/**
* 어려운 방법 (세션 정보 직접 찾기)
* Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
* PrincipalDetails principal = (PrincipalDetails) authentication.getPrincipal();
* principal.getUser();
*/
return "views/user/update";
}
}
- user/profile은 내 프로필 이외에도 다른 사람들의 프로필도 볼 수 있게 해야하기 때문에 @PathVariable을 사용해서 매핑
- update도 보기 쉽게 id로 구분했음
- @AuthenticationPrincipal 을 사용하면 PrincipalDetails를 바로 찾아줌 ➡️ 세션에 접근
PREV
NEXT
728x90
반응형
'프로젝트 > 인스타그램 클론 코딩' 카테고리의 다른 글
[인스타그램 클론 코딩][Spring boot] 6. 구독하기 (0) | 2024.02.19 |
---|---|
[인스타그램 클론 코딩][Spring boot] 5. 회원 정보 수정 (1) | 2024.02.19 |
[인스타그램 클론 코딩][Spring boot] 3. 회원 가입 구현 (2) | 2024.02.17 |
[인스타그램 클론 코딩][Spring boot] 2. Security 설정 (0) | 2024.02.16 |
[인스타그램 클론 코딩][Spring boot] 1. 프로젝트 설정 (0) | 2024.02.14 |