2023 여름 모각코 - 절개와지조

[모각코 / 230720] spring security 를 이용해 로그인 구현하기 (@EnableGlobalMethodSecurity)

pkyung 2023. 8. 17. 23:31
반응형

 

안녕하세요 모각코 5일차입니다. 

 

 

오늘은 spring security를 사용하여 로그인을 구현했습니다. 

 

 

 

그전에 spring security 설정을 해야한다면? https://p-kyung.tistory.com/78

 

[모각코 / 230713] spring security 기본적인 환경 설정

안녕하세요 모각코 3일차입니다. 원래는 객체지향의 사실과 오해를 모두 읽어보려하였으나 건강상의 문제로 책이 눈에 들어오지 않아 목표를 변경하여 spring security를 공부해보려합니다. spring se

p-kyung.tistory.com

 

회원가입을 구현하고 싶다면? https://p-kyung.tistory.com/79

 

[모각코 / 230715] spring security를 이용해 회원가입 구현하기

안녕하세요 모각코 4일차입니다. 오늘은 spring security를 사용하며 securityConfig 파일을 만들어서 각 페이지 별로 권한을 넣어주었습니다. 그리고 user 모델을 생성하고 jpa repository를 사용하여 회원가

p-kyung.tistory.com

 

 

 

SecurityConfig.java 파일 안의 filterChain에 두 줄을 추가합니다.

.loginProcessingUrl("/login") // /login 주소가 호출되면 security 가 낚아서 로그인을 진행함
.defaultSuccessUrl("/"); // 이전에 요청하지 않았을 경우 첫번째 페이지로 이동

 

 

/login 이 호출되면 security가 로그인을 처리하게 되는데 처리하는 과정이 auth 패키지 안에 들어갈 예정입니다.  

로그인 진행 완료 후 security session 을 만들게 되는데 session 안에는 Authentication 객체가 들어있고 그 안에는 UserDetails 객체가 들어있게 됩니다. 

 

아래의 경우에는 session 안에 Authentication 안에 PrincipalDetails가 들어있게 됩니다.  

 

 

 

PrincipalDetails의 경우 UserDetails interface를 상속받은 뒤, 메서드들을 override 하여 구현해줍니다.

/auth/PrincipalDetails/java

public class PrincipalDetails implements UserDetails {

    private User user;

    public PrincipalDetails(User user) {
        this.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 collect;
    }

    @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년 초과하면 false return 하도록 구현
        return true;
    }
}

 

이는 /login을 실행하면 바로 loadUserByUsername 함수를 실행하게 됩니다.

여기서는 login 시에 db안에 username에 맞는 user객체가 있는지 확인하는 과정입니다. (궁금한 점 : 여기서 비밀번호도 일치하는지 보나?)

auth/PrincipalDetailsService.java

// security 설정에서 loginProcessingUrl("/login")
// /login 요청이 오면 자동으로 UserDetailsService 타입으로 IoC되어 있는 loadUserByUsername 함수 실행
@Service
public class PrincipalDetailsService implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    // security session(내부 Authentication(내부 UserDetails))
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        User userEntity = userRepository.findByUsername(username);

        if (userEntity != null) {
            return new PrincipalDetails(userEntity);
        }

        return null;
    }
}

 

 

SecurityConfig.java에 이를 추가합니다. 

@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) // secured 어노테이션 활성화, PreAuthorize 어노테이션 활성화

 

securedEnabled는 @Secured 어노테이션을 활성화시키고 prePostEnabled는 @PreAuthorize 어노테이션을 활성화시킵니다. 메서드에 하나씩 권한을 걸고 싶을 경우 사용하게 되는 어노테이션입니다. 

IndexController.java

@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 "데이터 정보";
}

 

 

 

메타코딩님의 강의를 듣고 공부했습니다. 

 

https://youtu.be/uaEuT7ZfQI8

 

반응형