@postya

Как сделать логин для админа в Spring Security?

Приложение на Spring Security + Thymeleaf + Postgresql

Администрировать приложение буду только я, то есть будет только одна роль 'ADMIN'

Если пользователь захочет к примеру перейти на админский url "localhost:8080/admin/sketches" то нужно показать форму с логином, во всех остальных url форма логина не должна показываться.

Возникает несколько вопросов:

1.Как лучше и безопасней сделать логин, создать в памяти (in memory authentication) одного админа с именем и паролем, или создать админа в базе данных?

2. Как реализовать аутентификацию для админа в Spring Security?

Желательно,чтобы форма логина была своя, кастомная

Конфиг для Spring Security:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/**").hasAnyRole("ADMIN")
                .antMatchers("/**").permitAll()
        .and().exceptionHandling().accessDeniedPage("/error/access-denied.html")
        .and().csrf().disable();
    }

    @Override
    public void configure(WebSecurity web) {
        web.ignoring().antMatchers(

                // статика
                "/css/**",
                "/js/**",
                "/fonts/**",
                "../libs/**",
                "/images/**"
        );
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth)
            throws Exception {
        auth
                .inMemoryAuthentication()
                .withUser("admin").password(passwordEncoder().encode("password")).roles("ADMIN");
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}


Контроллер Админа:

@Controller
@RequestMapping("/admin/")
public class AdminController {

    @GetMapping("sketches")
    public String editSketches() {
        return "admin/sketches";
    }
}


Контроллер общий:

@Controller
public class HomeController {     
   
    @GetMapping("/home")
    public String home() {
        return "home";
    }
}
  • Вопрос задан
  • 633 просмотра
Решения вопроса 1
azerphoenix
@azerphoenix Куратор тега Spring
Java Software Engineer
Здравствуйте!
Я реализовал это следующим образом:
В данном случае у меня 2 кастомные формы входа:
1) для админ панели /admin/login
2) для пользователей /auth
/**
 * Конфигурация для Spring Security
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig {

    private static UserDetailsServiceImpl userDetailsService;

    @Autowired
    private UserDetailsServiceImpl userDetailsServiceImpl;

    @PostConstruct
    private void init() {
        userDetailsService = this.userDetailsServiceImpl;
    }

    @Bean
    public static PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public DaoAuthenticationProvider authProvider() {
        CustomAuthenticationProvider authProvider = new CustomAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService);
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }

    // Конфигурация для backend
    @Configuration
    @Order(1)
    public static class BackendConfigurationAdapter extends WebSecurityConfigurerAdapter {


        @Autowired
        private CustomWebAuthenticationDetailsSource authenticationDetailsSource;

        public BackendConfigurationAdapter() {
            super();
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {

            http
                    .antMatcher("/admin/**")
                    .antMatcher("/admin/**/**")
                    .authorizeRequests()
                    .anyRequest()
                    .hasAuthority("ADMIN_PRIVILEGE")
                    /*.hasAuthority("ADMIN")*/


                    .and()
                        .formLogin()
                        .authenticationDetailsSource(authenticationDetailsSource)
                        .loginPage("/admin/login")
                        .loginProcessingUrl("/admin/login")
                        .usernameParameter("email")
                        .passwordParameter("password")
                        .defaultSuccessUrl("/admin/dashboard")
                        .failureUrl("/admin/login?authError")
                        .permitAll()

                    .and()
                        .rememberMe()
                        .rememberMeParameter("remember-me")
                        .tokenValiditySeconds(86400)

                    .and()
                        .logout()
                        .logoutRequestMatcher(new AntPathRequestMatcher("/admin/logout"))
                        .logoutSuccessUrl("/admin/login")
                        .deleteCookies("JSESSIONID")

                    .and()
                        .exceptionHandling()
                        .accessDeniedPage("/403")

                    .and()
                        .csrf()
                        .ignoringAntMatchers("/admin/**");
        }

        @Override
        public void configure(WebSecurity web) {
            web.ignoring().antMatchers(

                    // статика backend
                    "/backend/css/**",
                    "/backend/js/**",
                    "/backend/fonts/**",
                    "/backend/images/**",
                    "/backend/init/**"

            );
        }


        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(userDetailsService);
        }

    }


    // Конфигурация для frontend (Обычная авторизация и авторизация oauth2)
    @Configuration
    @Order(2)
    public static class FrontendConfigurationAdapter extends WebSecurityConfigurerAdapter {

        @Autowired
        private CustomWebAuthenticationDetailsSource authenticationDetailsSource;

        public FrontendConfigurationAdapter() {
            super();
        }

        protected void configure(HttpSecurity http) throws Exception {

            http
                    .authorizeRequests().mvcMatchers("/robots.txt").permitAll()
                    .antMatchers(
                            "/", "/auth", "/signup", "/restore", "/activation/**",
                            "/admin/login", "/admin_restore",
                            "/attachments/get/**",
                            "/sendMessage",
                            "/error",
                            "/page/**",
                            "/categories", "/categories/**",
                            "/terms/**", "/posts", "/posts/**"
                    ).permitAll()
                    .anyRequest().authenticated()

                    .and()
                        .formLogin()
                        .authenticationDetailsSource(authenticationDetailsSource)
                        .loginPage("/auth")
                        .loginProcessingUrl("/auth")
                        .usernameParameter("email")
                        .passwordParameter("password")
                        .defaultSuccessUrl("/")
                        .failureUrl("/auth?authError")
                        .permitAll()

                    .and()
                        .rememberMe()
                        .rememberMeParameter("remember-me")
                        .tokenValiditySeconds(86400)

                    .and()
                        .oauth2Login().defaultSuccessUrl("/")

                    .and()
                        .logout()
                        .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                        .logoutSuccessUrl("/")
                        .deleteCookies("JSESSIONID")

                    .and()
                        .exceptionHandling()
                        .accessDeniedPage("/403")

                    .and()
                        .csrf()

                    .and()
                        .sessionManagement()
                        .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)

                    .and()
                        .headers().frameOptions().sameOrigin();
                    

        }

        @Override
        public void configure(WebSecurity web) {
            web.ignoring().antMatchers(
                    "/frontend/css/**",
                    "/frontend/js/**",
                    "/frontend/fonts/**",
                    "/frontend/images/**",
                    "/frontend/lib/**",
                    "/frontend/vendor/**"
            );
        }

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(userDetailsService);
        }


    }

}


Админа, как по мне, лучше создать при инициализации приложения. Вот, код, как это делаю я.

@Component
public class InitData implements CommandLineRunner {

@Override
public void run(String... args) throws Exception {
if (userServiceImpl.usersCount() == 0)
            initUsers();
}

private void initUsers() {
// создаем пользователей
}
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы