본문 바로가기

STUDY/Spring

Spring Boot | Spring Security OAuth2 (3) JDBC방식으로 바꾸기

 

이전까지 inMemory방식이었지만, 이제 JDBC방식으로 바꿔본다..

0. DB설정 및 테이블 생성

application.yml혹은 application.properties파일에서 설정해주기!

 

Spring Boot | MyBatis 연동

저번엔 Spring Framwork에 연동을 해봤고.. 이번엔 부트에... 해보자... 아자아자... 1. 라이브러리 추가 원하는 버전으로다가 넣어주십쇼 // Maven org.mybatis.spring.boot mybatis-spring-boot-starter 2.1.4 /..

gaemi606.tistory.com

아래 링크의 sql을 참고해서 만들면 되는데,

일단 oauth_client_details 테이블(클라이언트 정보가 담길 테이블)만 생성해주었다.

 

spring-projects/spring-security-oauth

Support for adding OAuth1(a) and OAuth2 features (consumer and provider) for Spring web applications. - spring-projects/spring-security-oauth

github.com

 

1. Oauth2AuthorizationConfig 수정

inMemory방식으로 설정해둔 부분을 주석처리 하거나 삭제한 후, jdbc방식으로 설정해준다.

passwordencoder를 설정해두었기 때문에 DB에도 인코딩 된 비밀번호 값이 들어가야한다.

@AllArgsConstructor
@Configuration
@EnableAuthorizationServer    // OAuth2 인증 서버를 사용하겠다는 뜻
public class Oauth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter {

    private final AuthenticationManager authenticationManager;

    private DataSource dataSource;

    private PasswordEncoder passwordEncoder;

    /* OAuth2 서버가 작동하기 위한 EndPoint에 대한 정보 설정 */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
    }

    /* 클라이언트 대한 정보를 설정하는 부분 */
    /* jdbc(DataBase)를 이용하는 방식 */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource).passwordEncoder(passwordEncoder);
    }

    /* inMemory 방식*/
//    @Override
//    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//        clients.inMemory()
//                .withClient("clientId")                              // 클라이언트 아이디
//                .secret("{noop}clientSecret")                               // 클라이언트 시크릿
//                .redirectUris("http://localhost:8081/oauth2/callback")      // 인증 결과를 수신할 URI
//                .authorizedGrantTypes("authorization_code", "password")     // 인증 방식
//                .scopes("read", "write")                                    // 해당 클라이언트의 접근 범위
//                .accessTokenValiditySeconds(60 * 60 * 4)                    // access token 유효 기간 (초 단위)
//                .refreshTokenValiditySeconds(60 * 60 * 24 * 120)            // refresh token 유효 기간 (초 단위)
//                .autoApprove(true);                                         // OAuth Approval 화면 나오지 않게 처리
//    }
}

 

그래서 일단 서버가 시작될 때 인코딩된 값을 출력하도록 해놨다...

@SpringBootApplication
public class Oauth2Application {

	public static void main(String[] args) {
		SpringApplication.run(Oauth2Application.class, args);

		PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
		System.out.println("endcode = " + passwordEncoder.encode("clientSecret"));
	}

}

 

그리고 인코딩된 값을 테이블에 insert해주기

insert into oauth_client_details(client_id, resource_ids, client_secret, 
scope, authorized_grant_types, web_server_redirect_uri, 
authorities, access_token_validity, refresh_token_validity, additional_information, autoapprove)
values("clientId", null, "{bcrypt}$2a$10$WJ1ZVWwZm/lY.hVlrGo4VejG7V7Mwscbdpy/DoEQema6SqZAnX9nm",
"read,write", "authorization_code,password", "http://localhost:8081/oauth2/callback",
"ROLE_USER", 36000, 50000, null, "true");

 

2. 테스트

http://localhost:8081/oauth/authorize?client_id=clientId&redirect_uri=http://localhost:8081/oauth2/callback&response_type=code&scope=read

 

포스트맨으로도 잘 된다!

 

여기까지 잘 되면, 우선 Client 정보를 DB에서 받아와 유효한지 체크할 수 있게 된 것이다!

이제 User정보도 DB에서 조회해 유효한지 체크해보자.. 이 부분은 일반 스프링 시큐리티와 거의 동일

 

 

3. USER 테이블 생성 및 INSERT

USER테이블은 자유롭게 만들면 되는데, name, password, role혹은 auth같은 값을 담을 컬럼 정도가 필요함.

여기서도 password인코딩 해주는 것 잊지 말자!

그리고 mapper작성 및 service... 다 합시다..

 

4. CustomAuthenticationProvider작성

@AllArgsConstructor
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    UserService userService;

    private final PasswordEncoder passwordEncoder;

    /* 유효한 회원 정보인지 확인하는 부분 */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        String username = authentication.getName();
        String password = authentication.getCredentials().toString();

        User findUser = userService.findByPk(username);

        if(!passwordEncoder.matches(password, findUser.getPassword())) {
            throw new BadCredentialsException("비밀번호가 일치하지 않음");
        }

       List<GrantedAuthority> authorityList = new ArrayList<>();
        authorityList.add(new SimpleGrantedAuthority(findUser.getAuthorities()));
        return new UsernamePasswordAuthenticationToken(username, password, authorityList);
    }

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

 

5. SecurityConfig 수정

우선 위에서 작성한 CustomAuthenticationProvider를 불러오고

 @Autowired
 private CustomAuthenticationProvider customAuthenticationProvider;

 

inMemory방식이었던 부분을 주석처리 혹은 삭제한 뒤 아래와 같이 작성한다.

    /* DB에서 user 조회 */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
       auth.authenticationProvider(customAuthenticationProvider);
    }

 

테스트 완

 

+) 참고

 

Spring Security Custom Authentication Provider | Baeldung

How to Set Up a Custom Authentication Provider with Spring Security and the namespace configuration.

www.baeldung.com

 

 

Secure spring boot with custom authentication | wstutorial.com

By Marone: December 2019 Goal This is part II of a series of articles on Spring security topic, The first part with basic authenticationcan be found here. Instead of using inMemoryAuthentication we will use for the frist time AuthenticationProvider to auth

wstutorial.com