김태오

Example implementation of a Spring Security File 본문

Spring Security

Example implementation of a Spring Security File

ystc1247 2023. 4. 16. 16:06

 

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 
    @Autowired
    private CustomUserDetailsService customUserDetailsService;
 
    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;
 
    @Autowired
    private CustomAccessDeniedHandler customAccessDeniedHandler;
 
    @Autowired
    private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
 
    @Autowired
    private CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
 
    @Autowired
    private CustomLogoutSuccessHandler customLogoutSuccessHandler;
 
    @Autowired
    private JwtRequestFilter jwtRequestFilter;
 
    @Autowired
    private DataSource dataSource;
 
    @Autowired
    private Environment environment;
 
    @Value("${security.oauth2.client.client-id}")
    private String clientId;
 
    @Value("${security.oauth2.client.client-secret}")
    private String clientSecret;
 
    @Value("${security.oauth2.client.access-token-uri}")
    private String accessTokenUri;
 
    @Value("${security.oauth2.client.user-authorization-uri}")
    private String userAuthorizationUri;
 
    @Value("${security.oauth2.resource.user-info-uri}")
    private String userInfoUri;
 
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(customUserDetailsService);
        auth.authenticationProvider(customAuthenticationProvider);
        auth.jdbcAuthentication().dataSource(dataSource)
            .usersByUsernameQuery("select username, password, enabled from users where username=?")
            .authoritiesByUsernameQuery("select username, role from user_roles where username=?")
            .passwordEncoder(passwordEncoder());
    }
 
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
                .antMatchers("/api/authenticate").permitAll()
                .antMatchers("/api/**").authenticated()
                .and()
            .oauth2Login()
                .loginPage("/login")
                .defaultSuccessURL("/home")
                .authorizationEndpoint()
                    .baseUri("/oauth2/authorize")
                    .authorizationRequestRepository(cookieAuthorizationRequestRepository())
                    .and()
                .redirectionEndpoint()
                    .baseUri("/oauth2/callback/*")
                    .and()
                .userInfoEndpoint()
                    .userService(oAuth2UserService)
                    .and()
                .successHandler(oAuth2AuthenticationSuccessHandler)
                .and()
            .exceptionHandling()
                .accessDeniedHandler(customAccessDeniedHandler)
                .and()
            .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
            .formLogin()
                .loginPage("/login")
                .successHandler(customAuthenticationSuccessHandler)
                .failureHandler(customAuthenticationFailureHandler)
                .and()
            .logout()
                .logoutUrl("/api/logout")
                .logoutSuccessHandler(customLogoutSuccessHandler)
                .and()
            .addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    }
 
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
 
    @Bean
    public OAuth2AuthorizedClientService authorizedClientService() {
        return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository());
    }
 
    @Bean
    public ClientRegistrationRepository clientRegistrationRepository() {
        List<ClientRegistration> registrations = List.of(
            ClientRegistration.withRegistrationId("my-client-id")
                .clientId(clientId)
                .clientSecret(clientSecret)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .redirectUri("{baseUrl}/login/oauth2/code/{registrationId}")
                .scope("read:user")
                .authorizationUri(userAuthorization
                            .accessTokenUri(accessTokenUri)
            	.userInfoUri(userInfoUri)
            	.userNameAttributeName(IdTokenClaimNames.SUB)
            	.clientName("My Client")
            	.build()
    );

    return new InMemoryClientRegistrationRepository(registrations);
}

@Bean
public OAuth2AuthorizationRequestRepository<OAuth2AuthorizationRequest> cookieAuthorizationRequestRepository() {
    return new HttpCookieOAuth2AuthorizationRequestRepository();
}

@Bean
public OAuth2UserService<OAuth2UserRequest, OAuth2User> oAuth2UserService() {
    DefaultOAuth2UserService delegate = new DefaultOAuth2UserService();
    return request -> {
        OAuth2User user = delegate.loadUser(request);

        // Custom logic to map OAuth2 user attributes to local user object
        CustomUser customUser = new CustomUser();
        customUser.setUsername(user.getAttribute("username"));
        customUser.setEmail(user.getAttribute("email"));
        customUser.setFirstName(user.getAttribute("given_name"));
        customUser.setLastName(user.getAttribute("family_name"));
        customUser.setEnabled(true);

        return customUser;
    };
}

@Bean
public OAuth2AuthenticationSuccessHandler oAuth2AuthenticationSuccessHandler() {
    return new CustomOAuth2AuthenticationSuccessHandler("/home");
}

CustomUserDetailsService: A custom implementation of Spring's UserDetailsService interface for retrieving user details from a database.

 

CustomAuthenticationProvider: A custom implementation of Spring's AuthenticationProvider interface for authentic

ating users using the custom UserDetailsService.

 

CustomAccessDeniedHandler: A custom implementation of Spring's AccessDeniedHandler interface for handling unauthorized access attempts.

 

CustomAuthenticationSuccessHandler: A custom implementation of Spring's AuthenticationSuccessHandler interface for handling successful authentication attempts.

 

CustomAuthenticationFailureHandler: A custom implementation of Spring's AuthenticationFailureHandler interface for handling failed authentication attempts.

 

CustomLogoutSuccessHandler: A custom implementation of Spring's LogoutSuccessHandler interface for handling successful logout attempts.

 

JwtRequestFilter: A custom filter for authenticating requests using JSON Web Tokens (JWT).
DataSource: A standard Spring DataSource object for connecting to a database.

 

configure(AuthenticationManagerBuilder auth) method 

configures how the application authenticates users. In this case, it sets up the custom UserDetailsService and AuthenticationProvider, and also configures a JDBC authentication provider using the dataSource object. The usersByUsernameQuery and authoritiesByUsernameQuery methods specify the SQL queries used to retrieve user details and roles from the database. The passwordEncoder method specifies the password encoder to use for hashing and comparing passwords.