본문 바로가기
Spring/SpringBoot

[goormedu 강의] 스프링부트 블로그 만들기 06 - 05 스프링 시큐리티 로그인

by 코딩맛 2024. 10. 5.
해당 글은 groomedu의 스프링부트 나만의 블로그 만들기 강의를 보고 개인적으로 정리한 글입니다.

 

loginForm.jsp

<form action="/auth/loginProc" method="post">
	<div class="form-group">
		<label for="username">Username</label> 
		<input type="text" name="username" class="form-control" placeholder="Enter username" id="username">
	</div>
	<div class="form-group">
		<label for="password">Password</label> 
		<input type="password" name="password" class="form-control" placeholder="Enter password" id="password">
	</div>
	<button id="btn-login" class="btn btn-primary">로그인</button>
</form>

로그인 버튼 클릭 시 form action 주소로 이동한다.

UserApiController에 '/auth/loginProc'에 POST 매핑되는 메소드를 선언하지 않고

스프링 시큐리티에서 가로채기 하게 한다.

 

SpringConfig.java

@Bean
public SecurityFilterChain configure(HttpSecurity http) throws Exception {	
	 http
		.csrf().disable() // csrf 토큰 비활성화
		.authorizeRequests()
	    	.requestMatchers("/**", "/auth/**", "/js/**", "/css/**", "/image/**")
	    	.permitAll()
	    	.anyRequest()
	    	.authenticated()
        .and()
		.formLogin()
		.loginPage("/auth/loginForm")
		.loginProcessingUrl("/auth/loginProc")// 스프링 시큐리티가 해당 주소로 요청오는 로그인을 가로채서 대신 로그인 해준다.
		.defaultSuccessUrl("/");//로그인이 성공하면 "/" 경로로 이동
	  return http.build();
}

 

.loginProcessingUrl("/auth/loginProc")// 스프링 시큐리티가 해당 주소로 요청오는 로그인을 가로채서 대신 로그인 해준다.
.defaultSuccessUrl("/");//로그인이 성공하면 "/" 경로로 이동

.loginProcessingUrl() : 스프링 시큐리티가 () 안에 주소로 요청이 오는 로그인을 가로채서 로그인

.defaultSuccessUrl() : 정상 요청 시 () 안에 주소로 이동

 

로그인 시에 이름과 비밀번호를 입력받아서 DB에 있는지 확인해야한다.

로그인 진행 후 UserDetails 타입의 오브젝트를 세션저장소에 저장해야하기 때문에 UserDetails 선언 필요

 

PrincipalDetail (UserDetails 타입의 오브젝트)

public class PrincipalDetail implements UserDetails{
	private User user; // 콤포지션: 객체를 품고 있는 것.

	public PrincipalDetail(User user) {
		this.user = user;
	}

	@Override
	public String getPassword() {
		return user.getPassword();
	}

	@Override
	public String getUsername() {
		return user.getUsername();
	}

	// 계정이 만료되지 않았는지 리턴한다.(true:만료안됨)
	@Override
	public boolean isAccountNonExpired() {
		return true;
	}

	// 계정이 잠겨있는지 아닌지 리턴한다.(true:잠기지 않음)
	@Override
	public boolean isAccountNonLocked() {
		return true;
	}

	// 비밀번호가 만료됐는지 안 됐는지 리턴한다.(true:만료 안 됨)
	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}

	// 계정이 활성화(사용가능)인지 리턴한다. (true:활성화)
	@Override
	public boolean isEnabled() {
		return true;
	}
	
	// 계정의 권한 목록을 리턴한다.
	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		Collection<GrantedAuthority> collectors = new ArrayList<>();
		
		// GrantedAuthority 인터페이스에 메소드는 getAuthority() 하나이기에 아래와 같이 람다식으로 선언가능
		collectors.add(()->{return "ROLE_"+user.getRole();});
		
		return collectors;
	}
}

 

getAuthorties() : 계정의 권한 목록을 리턴함

스프링은 권한이 “ROLE_”로 시작하기 때문에 붙여서 리턴

람다식을 사용하여 collectors에 권한을 add하여 리턴

 

PrincipalDetailService

@Service
public class PrincipalDetailService implements UserDetailsService{
	
	@Autowired
	private UserRepository userRepository;

	// 스프링이 로그인 요청을 가로챌때, username, password 변수 2를 가로채는데
	// password 부분은 알아서 함.
	// username이 DB에 있는지만 확인해주면 됨.
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		User principal = userRepository.findByUsername(username)
				.orElseThrow(()->{
					return new UsernameNotFoundException("해당 사용자를 찾을 수 없습니다. :"+username);
				});
		return new PrincipalDetail(principal); //시큐리티의 세션에 유저 정보가 저장이 됨.
	}
}

loadUserByUsername() 함수에서 DB에 username이 있는지 체크

password가 틀린 것은 스프링 시큐리티에서 알아서 처리

리턴하는 PrincipalDetail(UserDetails 타입의 유저 정보)가 스프링 시큐리티 세션에 저장됨.

 

SecurityConfig

// 시큐리티가 대신 로그인 해주는데 password를 가로채기 하는데
// 해당 password가 뭘로 해쉬 되어 회원가입이 되었는지 알아야 
// 같은 해쉬로 암호화해서 DB에 있는 해쉬랑 비교할 수 있음.
public void configure(AuthenticationManagerBuilder auth) throws Exception {	
	auth.userDetailsService(principalDetailService).passwordEncoder(encodePWD());
}

 

configure() 함수를 선언하여 입력 받은 비밀번호를 해쉬화한 값과 DB에 저장된 값과  비교한다.

 

** 이 부분은 스프링 최신 버전에서는 DI한 SecurityFilterchain에서 자동으로 PrincipalDetailService를 불러와서 비교하므로 제거

 

로그인 페이지, 로그인 성공했을 때 페이지

 

로그인 정보를 입력 후 성공하면 우측 화면과 같이 메뉴가 바뀐 것을 확인할 수 있다.