-
Spring Security - 로그인Framework & Library/Spring Security 2021. 10. 1. 15:06
로그인 설정
SecurityConfig 클래스 수정
@Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable(); http.authorizeRequests() .antMatchers("/user/**").authenticated() // 인증 필요 .antMatchers("/manager/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_MANAGER')") // ROLE_ADMIN, ROLE_MANAGER 권한 필요 .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')") // ROLE_ADMIN 권한 필요 .anyRequest().permitAll() // 다른 요청은 모두 허용 .and().formLogin().loginPage("/loginForm") // 로그인 페이지의 기본 경로를 설정 .loginProcessingUrl("/login") .defaultSuccessUrl("/"); }
ㆍ SecurityConfig 클래스의 configure() 메서드를 위 코드와 같이 수정한다.
ㆍ loginPrecessinUrl("/login") 메서드는 지정된 주소가 호출이 되면 시큐리티가 낚아채서 대신 로그인을 수행해준다. 따라서 Controller 영역에 로그인을 수행하는 메서드를 구현할 필요가 없다.
ㆍ.defaultSuccessUrl("/") 메서드는 로그인이 완료되면 이동 url을 설정하는 메서드이다.
loginForm.html 수정
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>로그인 페이지</title> </head> <body> <h1>로그인 페이지</h1> <hr/> <form action="/login" method="post"> <input type="text" name="username" placeholder="Username"/> <br/> <input type="password" name="password" placeholder="Password"/> <br/> <button>로그인</button> </form> <a href="/oauth2/authorization/google">구글 로그인</a> <a href="/joinForm">회원가입</a> </body> </html>
ㆍ 로그인을 수행하기 위해 위 코드와 같이 action과 method 속성을 추가해준다.
UserDetails 구현
Spring Security Session
ㆍ 스프링은 로그인이 정상적으로 완료되면 스프링 시큐리티를 위한 Session을 만들어 로그인 처리를 해준다.
ㆍ 이때, 스프링 시큐리티 Session에 들어갈 수 있는 객체는 Authentication이어야 한다.
Authentication
ㆍ 스프링 시큐리티 Session안에 있는 Authentication 객체는 로그인을 한 User에 대한 정보가 들어있어야 한다.
ㆍ 이때 User의 타입은 그냥 User 객체가 아닌 UserDetails 타입이어야 한다.
UserDetails의 구현
@Data public class PrincipalDetails implements UserDetails { private User user; public PrincipalDetails(User user) { this.user = user; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { return null; } @Override public String getPassword() { return null; } @Override public String getUsername() { return null; } @Override public boolean isAccountNonExpired() { return null; } @Override public boolean isAccountNonLocked() { return null; } @Override public boolean isCredentialsNonExpired() { return null; } @Override public boolean isEnabled() { return null; } }
ㆍ config 패키지 내에 auth 패키지를 생성하고 PrincipalDetails 클래스를 만든다.
ㆍ PrincipalDetails 클래스는 UserDetails 구현하고 메서드들을 오버라이딩하는 형태이다.
ㆍ 클래스 내에 사용자 정보를 가지고 있는 User 객체를 선언하고, 생성자를 만든다.
ㆍ PrincipalDetails 클래스를 통해 로그인에 대한 다양한 처리가 가능한다.
getAuthorities() 메서드 오버라이딩
@Override public Collection<? extends GrantedAuthority> getAuthorities() { Collection<GrantedAuthority> collection = new ArrayList<>(); collection.add(new GrantedAuthority() { @Override public String getAuthority() { return user.getRole(); } }); return collection; }
ㆍ getAuthorities() 메서드는 로그인을 한 사용자의 권한을 리턴하는 메서드이다.
ㆍ 현재 User 객체의 role 변수의 타입이 String이기 때문에 시큐리티가 인식하기 위해서는 변환이 필요하다.
ㆍ getAuthorities() 메서드를 오버라이딩 함으로써 String 타입의 권한을 GrantedAuthority 타입으로 변환한다.
UserDetailsService 구현
UserDetailsService
ㆍ 로그인 요청이 오면 DB에서 사용자 정보를 가져와 비교하는 과정을 거치게 된다.
ㆍ 해당 과정을 수행하는 인터페이스가 바로 UserDetailsService이며, 로그인 요청이 오게 되면 인터페이스 내 loadUserByUsername() 메서드가 수행됨으로써 그 역할을 수행한다.
PrincipalDetailsService 클래스
@Service public class PrincipalDetailsService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return null; } }
ㆍ auth 패키지에 PrincipalDetailsService 클래스를 생성하고 UserDetailsService 인터페이스를 구현한다.
ㆍ loadUserByUsername() 메서드를 오버라이딩 함으로써 DB 내의 사용자 정보를 불러오도록 한다.
loadUserByUsername() 메서드 오버라이딩
@Service public class PrincipalDetailsService implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User userEntity = userRepository.findByUsername(username); if (userEntity != null) { // DB에 등록된 사용자 이름이 있는지 확인 return new PrincipalDetails(userEntity); } return null; } }
ㆍ DB에 접근하기 하기 위해 UserReository 객체를 선언한다.
ㆍ loadUserByUsername() 메서드를 위 코드와 같이 작성한다.
ㆍ DB에 사용자 정보가 있다면 PrincipalDetails 객체를 리턴하고, 그렇지 않으면 null을 리턴한다.
ㆍ loadUserByUsername() 메서드에 의해서 리턴된 PrincipalDetails 객체는 Authentication 객체에 들어가게 되고, Authentication 객체는 스프링 시큐리티 Session 안에 들어가게 됨으로써 로그인이 완료된다.
GitHub - qlsdud0604/spring-security-basic: 스프링 시큐리티의 기초를 학습하는 공간
스프링 시큐리티의 기초를 학습하는 공간. Contribute to qlsdud0604/spring-security-basic development by creating an account on GitHub.
github.com
728x90'Framework & Library > Spring Security' 카테고리의 다른 글
Spring Security - 구글 로그인 준비 (0) 2021.10.02 Spring Security - 권한 처리 (0) 2021.10.01 Spring Security - 회원가입 (0) 2021.09.30 Spring Security - 시큐리티 설정 (0) 2021.09.30 Spring Security - 프로젝트 생성 및 환경설정 (0) 2021.09.30