로그인을 구현하기위해서 auth 패키지를 생성한다.
auth 패키지는 Spring Security가 로그인을 진행한다. 그 때 로그인이 완료가 되면 Security Session을 만들어준다 ( security contextholder 안에 저장)
이 Session 에 들어가는 정보 Object 가 정해져 있는데 이것이 바로 Authentication 객체여야 한다.
Authentication 안에는 User 정보가 있어야 한다 -> User Object의 type은 UserDetails type 객체여야한다.
즉 Spring Security => Authentication 객체 => UserDetails 객체
이렇게 있다는 뜻이다.
package com.cos.securiy1.auth;
import com.cos.securiy1.model.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
import java.util.Collection;
public class PrincipalDetails implements UserDetails {
private User user; // 컴포지션
public PrincipalDetails(User user){
this.user = user;
}
// 해당 User의 권한을 리턴하는곳.
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> collect = new ArrayList<>();
collect.add(new GrantedAuthority() {
@Override
public String getAuthority() {
return user.getRole();
}
});
return null;
}
// User 의 password 리턴
@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년동안 로그인을 안하면 휴먼계정을 전환을 하도록 하겠다.
// -> loginDate 타입을 모아놨다가 이 값을 false로 return 해버리면 된다.
return true;
}
}
package com.cos.securiy1.auth;
import com.cos.securiy1.model.User;
import com.cos.securiy1.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
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;
@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){
return new PrincipalDetails(userEntity);
}
return null;
}
}
package com.cos.securiy1.repository;
import com.cos.securiy1.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
// CRUD 함수를 들고있음
// @Repository 어노테이션이 없어도 IOC가 된다.
public interface UserRepository extends JpaRepository<User,Integer> {
// findBy규칙 -> Username 문법
// select * from user where username = ?
public User findByUsername(String username);
}
User의 정보에는 ROLE 이라는 변수가 있다.
권한에 따라서 사용자가 들어갈 수 있는 페이지를 처리하는것이다.
테스트를 위해 MySQL에서 일부 유저를 "ROLE_MANAGER","ROLE_ADMIN"으로 수정한다.
이렇게 하면 기존에 설정했던 /manager , /admin 페이지를 접근할 수 있는 권한이 생기는 것이다.
이 때, 기존에 SecurityConfig에 설정해 놓지 않은 주소들 또한 권한처리를 할수 있다.
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
다음과 같은 Annotation을 SecurityConfig에 추가한다.
그렇게하면
다음과 같은 어노테이션을 사용할 수 있다.
사용 방법은 아래와 같이 하면 된다.
@Secured("ROLE_ADMIN")
@GetMapping("/info")
public @ResponseBody String info(){
return "개인정보";
}
@PreAuthorize("hasRole('ROLE_MANAGER') or hasRole('ROLE_ADMIN')")
@GetMapping("/data")
public @ResponseBody String data(){
return "데이터정보";
}
다음과 같이 Security 에서 로그인을 처리하고 권한을 처리하는 방법을 해보았다.
다음에는 OAuth2를 이용하여 기존 로그인 뿐 만 아니라 구글,페이스북,네이버 같은 다른 사이트에서 로그인하는것을 해보려고 한다!