Spring security 기본

roon2020·2021년 6월 3일
0

spring

목록 보기
15/16
post-thumbnail

인증/인가

인증(Authentication), 인가(Authorization)를 하기 위해 Spring security 사용

  1. 인증 : 자신을 증명하는 것
  2. 인가 : 인증을 통해 받은 정보로 허가/제한을 하는 것(Access control)

Overview

  • 여러 필터가 동작한다. (filter chain)
  • 여러 객체가 정보를 주고받으면서 동작한다.
  • 필터들(filter chain) -> Authentication Manager -> Authentication Provider -> UserDetailsService

동작 흐름

  1. 사용자가 url 입력
  2. 사용자가 인증하도록 로그인 화면 보여주기
  3. Authentication Manager가 적절한 Authentication Provider를 찾아서 인증
    Authentication Provider는 실제로 UserDetailsSerivce를 구현한 객체를 이용해서 처리
  4. 인가과정에서 문제가 없으면 정상적인 화면을 보여주게 됨.

실제 구현

의존성

Initializr로 생성할 때 security -> spring security 선택.
또는 pom.xml에 spring-boot-starter-security 의존성 추가

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

의존성을 추가하고 external libraries에 가보면 시큐리티 관련 의존성들이 포함된 것을 볼 수 있음.

Security 설정 클래스

WebSecurityConfigurerAdapter

WebSecurityConfigurerAdapter에 정의된 메서드들을 override해서 쉽게 인증,인가 설정 가능

override configure(AuthenticationManagerBuilder)

  • 인증 (신분증 등록)
    AuthenticationManager를 쉽게 설정할 수 있도록 AuthenticationManagerBuilder를 제공.
    spring data jpa를 사용하면 따로 UserDetailsService를 작성하기 때문에 사용하지 않음.

override configure(HttpSecurity)

  • 인가 (신분 검사,접근 제한)
    특정 URL(리소스)에 접근 제한 설정 가능.

PasswordEncoder

  • 비밀번호 인코더 사용은 필수
    Spring에서 제공하는 bcrypt 인코더 사용 가능.
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
   @Bean
    PasswordEncoder passwordEncoder(){
       return new BCryptPasswordEncoder();
   }

   //직접 Authentication Manager를 설정할 수 있도록 해주는 cofigure(매니저빌더) 메서드도 있다.
    //UserDetailsService를 구현한 클래스를 따로 만들었으면 이 부분은 사용하지 않음.

    //특정 URL(리소스)에 접근 제한 설정하기
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/reserve").hasRole("USER");

        http.formLogin();
        http.csrf().disable();
        http.logout();

    }
}

JPA Repository

DB에서 사용자 정보를 꺼내와야 하기 때문에 JPA repository 필요.
따라서 Entity class,MemberRepository를 작성. 그리고 userDetailsService를 implements한 service 클래스,
User 클래스를 extends하여 만든 DTO도 작성.

//entity 
@Getter
@ToString
@NoArgsConstructor
@Entity
public class Member {
    @Id
    private String email;

    private String password;
    private String name;

    @Enumerated(value = EnumType.STRING)
    private MemberRole memberRole;

    @Builder
    public Member(String email, String name,String password) {
        this.email = email;
        this.name = name;
        this.password = password;
    }

    public void setMemberRole(MemberRole memberRole) {
        this.memberRole = memberRole;
    }
}
//dto
@ToString
@Getter
@Setter
public class MemberDTO extends User {
    private String email;
    private String name;

    public MemberDTO(String username, String password,
    Collection<? extends GrantedAuthority> authorities){
        super(username,password,authorities);
        this.email = username;
    }
}
//repository layer
public interface MemberRepository extends JpaRepository<Member,String> {
    Optional<Member> findByEmail(String email);
}
//user type
public enum MemberRole {
    USER("USER"),ADMIN("ADMIN");

    private final String typeName;

    private MemberRole(String typeName){
        this.typeName = typeName;
    }

    public String getTypeName(){
        return typeName;
    }
}
//service layer
@Service
public class MemberDetailsService implements UserDetailsService {
    @Autowired
    private MemberRepository memberRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Optional<Member> result = memberRepository.findByEmail(username);

        if (result.isPresent() == false) {
            throw new UsernameNotFoundException("user not found");
        }

        Member member = result.get();

        Collection<SimpleGrantedAuthority> authList = new ArrayList<>();
        authList.add(new SimpleGrantedAuthority("ROLE_"+member.getMemberRole().getTypeName()));

        MemberDTO dto = new MemberDTO(member.getEmail(),member.getPassword(),authList);
        dto.setName(member.getName());

        return dto;
    }
}

자세한 구성 요소,동작

Filter chain

  • 다양한 filter들이 체인 형식으로 구성되어 request 처리.
    filter 내에 다양한 객체들이 있음.

AuthenticationManager

  • 토큰(아이디,패스워드)
    Authenticate authenticate(Authentication 토큰)
    AuthenticationProvider를 이용해 인증.

AuthenticationProvider

  • authenticate()
    UserDetailsService 사용

UserDetailsService

  • 실제 인증을 위한 데이터를 가져옴.
    JPA와 UserDetailsService를 활용해 사용자 인증 정보 처리.
    UserDetailsService는 loadUserByUsername()라는 하나의 메서드만 가지고 있음
  • 참고 : 코드로 배우는 스프링부트
profile
keep in positive mindset. I've got this.

0개의 댓글