250x250
jhs0129
프로그래밍
jhs0129
전체 방문자
오늘
어제
  • 분류 전체보기
    • 자격증
      • SQLD
      • 정보처리기사
    • 프로젝트
      • html csss js - todolist
      • JSP 방명록
      • 졸업작품
    • 공부기록
      • Java
      • Spring
      • Spring Security
      • Algorithm
      • JPA
      • DB
      • Servlet JSP
      • html
      • 기술공유
    • 잡다한 생각

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • NHN Cloud
  • Spring Security Login
  • EC2
  • 스프링
  • nhn cloud 강의
  • github
  • 스프링시큐리티
  • oAuth2
  • spring boot
  • rest docs
  • Spring Security
  • 스프링 프레임워크
  • codedeploy
  • spring
  • cicd
  • AWS
  • 프로젝트
  • spring data jpa
  • spring framework
  • JPA

최근 댓글

최근 글

티스토리

반응형
hELLO · Designed By 정상우.
jhs0129

프로그래밍

공부기록/Spring Security

[추가]CustomAuthenticationProvider vs DaoAuthenticationProvider

2022. 12. 22. 10:01
320x100
반응형

목차

  • [이론] 스프링 시큐리티 1
  • [이론] 스프링 시큐리티2
  • [실습] 스프링 시큐리티 Form Login
  • [추가] CustomAuthenticationProvider vs DaoAuthenticationProvider
  • [이론] 스프링 시큐리티3
  • [이론] 스프링 시큐리티4
  • [추가] AuthorizeReqeusts vs AuthorizeHttpRequests
  • [실습] 스프링 시큐리티 Json data Login 처리
  • [실습] 스프링 시큐리티 JWT 설정
  • [실습] 스프링 시큐리티 JWT 처리
  • OAuth2

우리가 직접 만든 CustomAuthenticationProvider와 Spring Security 에서 제공되는 DaoAuthenticationProvider를 비교해보자

CustomAuthenticationProvider

public class CustomAuthenticationProvider implements AuthenticationProvider {

    private final UserService userService;
    private final PasswordEncoder passwordEncoder;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String password = authentication.getPrincipal().toString();
        UserDetails user = userService.loadUserByUsername(username);

        if (passwordEncoder.matches(password, user.getPassword())) {
            return new UsernamePasswordAuthenticationToken(
                    user.getUsername(),
                    user.getPassword(),
                    user.getAuthorities()
            );
        }
        throw new BadCredentialsException("BAD Credentials");
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.isAssignableFrom(UsernamePasswordAuthenticationToken.class);
    }
}

직접 만든 Provider에서 진행되는 작업은

  1. Authentication 객체로 부터 username, password 받아오기
  2. 정보를 토대로 사용자 찾기
  3. 비밀번호 검증
  4. 토큰 생성

1번 과정은 사용자가 보내준 정보를 읽어오는 과정이고 2,3번 과정에서 해당 사용자를 인증하는 과정이다

DaoAuthenticationProvider

public abstract class AbstractUserDetailsAuthenticationProvider
        implements AuthenticationProvider {
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        //1.
        String username = determineUsername(authentication); 
        boolean cacheWasUsed = true;
        UserDetails user = this.userCache.getUserFromCache(username);
        if (user == null) {
            cacheWasUsed = false;
            try {
                //2.
                user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication); 
            }
            //생략
        }
        try {
            // 생략 --> AccountLock, Enabled, Expired 확인과정
            //3.
            additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
        }
        //생략 Credentails 확인과정
        //생략 User cache에 넣어두기
        Object principalToReturn = user;
        if (this.forcePrincipalAsString) {
            principalToReturn = user.getUsername();
        }
        //4.
        return createSuccessAuthentication(principalToReturn, authentication, user);
    }

    public boolean supports(Class<?> authentication) {
        return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
    }
}

retrieveUser()와 additionalAuthenticationChecks()는 추상 메소드로 해당 객체 AbstractUserDetailsAuthenticationProvider를 상속받은 DaoAuthenticationProvider내부에서 재정의 되어있다

@Override
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
        throws AuthenticationException {
    prepareTimingAttackProtection();
    try {
        UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
        if (loadedUser == null) {
            throw new InternalAuthenticationServiceException(
                    "UserDetailsService returned null, which is an interface contract violation");
        }
        return loadedUser;
    }
    //생략
}
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails,
        UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
    String presentedPassword = authentication.getCredentials().toString();
    if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
        throw new BadCredentialsException();
    }
}

DaoAuthenticationProvider 코드도 생략된 부분을 제외하곤 다음과 같은 과정을 거친다

  1. Authentication 객체로 부터 username 받아오기
  2. username 기반으로 user찾기
  3. 해당 user정보와 Authentication 객체로 부터 받은 password 비교
  4. 토큰 생성

다음과 같이 확인 해본 결과 검증로직이 추가로 더 들어간 것과 약간의 순서 차이를 제외하곤 CustomProvider와 DaoProvider의 차이는 없다

굳이 직접 만들어서 사용하는 것보다 제공되는 것을 사용해도 괜찮을 듯 하다

하지만 한 번 정도는 직접 작성해서 사용해보는 것을 추천한다

왜 Service를 넣어주는지 PasswordEncoder를 왜 주어야 하는지 모른 상태로 따라만 하는 것 보다 훨씬 더 이해하기 쉬울 것이고 나중에 제공되는 것을 사용하더라도 어려움없이 사용이 가능 할 것이다

320x100
반응형

'공부기록 > Spring Security' 카테고리의 다른 글

[이론] 스프링 시큐리티4  (0) 2022.12.28
[이론] 스프링 시큐리티3  (0) 2022.12.26
[실습] 스프링시큐리티 로그인처리  (2) 2022.12.21
[이론] 스프링 시큐리티2  (1) 2022.12.21
[이론] 스프링 시큐리티1  (1) 2022.12.18
    '공부기록/Spring Security' 카테고리의 다른 글
    • [이론] 스프링 시큐리티4
    • [이론] 스프링 시큐리티3
    • [실습] 스프링시큐리티 로그인처리
    • [이론] 스프링 시큐리티2
    jhs0129
    jhs0129
    공부기록 남기기

    티스토리툴바