SecurityConfig
...
.and()
.formLogin().loginPage("/loginForm")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/");
.loginProcessingUrl("/login")
/login 주소가 호출되면 시큐리티가 낚아채서 대신 로그인을 진행해 준다. 따라서 Controller에 login 기능을 따로 만들지 않아도 된다.
.defaultSuccessUrl("/");
로그인이 완료되면 /를 호출하여 index 페이지로 이동하게 한다.
loginForm.html
...
<h1>로그인 페이지</h1>
<hr>
<form action="/login" method="post">
<input type="text" name="username" placeholder="Username"><br>
<input type="password" name="password" placeholder="Password">
<button>로그인</button>
</form>
...

시큐리티가 /login 주소 요청이 오면 낚아채서 로그인을 진행시킨다. 로그인 진행이 완료되면 시큐리티 session을 만들어준다. Security ContextHolder에 세션 값을 저장을 하게 된다. 이때 시큐리티 세션에 들어갈 수 있는 Object는 정해져 있다.
오브젝트 타입은 Authentication 타입 객체이다. 이 Authentication 안에 User 정보가 있어야 하는데, User 오브젝트 타입은 UserDetail 타입 객체이다.
- Security Session
- Authentication
- UserDetails
- Authentication
package com.cos.security.config.auth;
import com.cos.security.model.User;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
import java.util.Collection;
// Security Session => Authentication => UserDetails(여기서는 PrincipalDeatils 가 된다.)
@RequiredArgsConstructor
public class PrincipalDetails implements UserDetails {
private final User user; //콤포지션
// 해당 User의 권한을 리턴하는 곳!!
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> collection = new ArrayList<>();
collection.add(new GrantedAuthority() {
@Override
public String getAuthority() {
return user.getRole();
}
});
return collection;
}
@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() {
// 우리 사이트에서 1년동안 회원이 로그인을 안하면, 휴면 계정으로 하기로 함.
// 현재시간 - 로그인시간 => 1년을 초과하면 return false
return true;
}
}

package com.cos.security.config.auth;
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;
// 시큐리티 설정에서 loginProcessingUrl("/login");
// login 요청이 오면 자동으로 UserDetailsService 타입으로 IoC되어 있는 loadUserByUsername 함수가 실행
@Service
public class PrincipalDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return null;
}
}
loginForm.html
<input type="text" name="username" placeholder="Username"><br>
name 속성의 username이 loadUserByUsername(String username)의 username과 매칭된다. 만약 html에서 name 속성의 값을 바꾸고 싶다면
SecurityConfig에서
...
.formLogin().loginPage("/loginForm")
.usernameParameter("바꾼값")
.loginProcessingUrl("/login")
...
이처럼 변경해줘야 한다.
계속 PrincipalDetailsService 클래스를 작성해 보자
@RequiredArgsConstructor
@Service
public class PrincipalDetailsService implements UserDetailsService {
private final UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User userEntity = userRepository.findByUsername(username);
return null;
}
}
UserRepository는 기본적인 CRUD 함수만 존재하고 findByUsername 같은 함수는 없다. 따라서 UserRepository에 findByUsername 함수를 만들어준다.
UserRepository
public interface UserRepository extends JpaRepository<User, Integer> {
public User findByUsername(String username);
}
위 함수에서 findBy 까지는 규칙이고, 그다음 Username은 문법이다. 위와 같이 함수명을 적으면
select * from user where username = ?
위 쿼리문이 실행된다.
( JPA 쿼리 메서드라고 검색)
최종
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User userEntity = userRepository.findByUsername(username);
if (userEntity != null) {
return new PrincipalDetails(userEntity);
}
return null;
}
이제 스프링부트를 재시작하고 로그인을 해보자. 그런데 User 테이블을 보면 아까 회원가입을 했는데도 정보가 없다.

그 이유는 application.properties에
spring.jpa.hibernate.ddl-auto=create
create로 되어 있기 때문이다. 새로 만들어지기 때문에 아까의 정보가 날아간 것이다. 이것을 update로 변경하자
spring.jpa.hibernate.ddl-auto=update
다시 회원가입을 하고

localhost:8080/logout을 입력해 우선 로그아웃을 하고 로그인 페이지에서 로그인을 해보자
로그인에 성공하면 인덱스 페이지로 오게 된다.

다시 로그아웃을 하고 /user로 접속해 보면 로그인 페이지로 가게 된다. 여기서 로그인을 하면 내가 가려고 했던 페이지인 /user 페이지로 바로 가진다.
'Spring Security' 카테고리의 다른 글
| [OAuth] 구글 로그인 준비 (0) | 2023.03.26 |
|---|---|
| [기본] 시큐리티 권한처리 (0) | 2023.03.25 |
| [기본] 시큐리티 회원가입 (0) | 2023.03.25 |
| [기본] 시큐리티 설정 (0) | 2023.03.25 |
| [기본] 환경 설정 (0) | 2023.03.25 |