Безопасность Spring: сделайте каждую страницу перенаправленной, если пользователь не соответствует определенным критериям - PullRequest
0 голосов
/ 03 июня 2019

Я занимаюсь разработкой веб-приложения, которое использует Spring Security в качестве поставщика аутентификации / авторизации.Вот как я его настраиваю:

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

        //Allow resources for all pages
        .antMatchers("/css/**", "/images/**", "/webjars/**").permitAll()

        //Allow or disallow specific routes depending on user privileges

        //Users
        .antMatchers("/users/", "users/search").hasAuthority("View Users")
        .antMatchers("/users/add", "/users/edit/*", "/users/delete/*").hasAuthority("Edit Users")

        .antMatchers("/roles/", "roles/search").hasAuthority("View Roles")
        .antMatchers("/roles/add", "/roles/edit/*", "/roles/delete/*").hasAuthority("Edit Roles")

        .antMatchers("/permissions/", "permissions/search").hasAuthority("View Permissions")

        //A million other antMatchers here...

        //All custom routes require authentication
        .anyRequest().authenticated()

        //Custom login page and handling
        .and()
            .formLogin()
            .loginPage("/login")
            .loginProcessingUrl("/perform_login")
            .successHandler(loginHandler())
            .failureUrl("/login_error")             
            .permitAll()

        //Custom logout handling with POST request and logout handler for auditing
        .and()
            .logout()
            .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
            .logoutSuccessHandler(logoutHandler())
            .logoutSuccessUrl("/logout_success")
            .permitAll()

        //Invalidate the session and delete the JSESSIONID cookie on logout
        .invalidateHttpSession(true)
        .deleteCookies("JSESSIONID");
}

Я не хочу публиковать слишком много кода (я буду при необходимости), но по сути мои пользователи хранятся в базе данных, и я использую расширение UserDetails и UserDetailsService длявзаимодействовать между Spring Security и БД.В моей сущности User у меня есть логическое поле, которое контролирует, нужно ли пользователю менять свой пароль (первый вход в систему).Чтобы достичь этой функциональности при входе пользователя в систему, у меня есть следующий AuthenticationSuccessHandler:

    public class LoginHandler implements AuthenticationSuccessHandler
{
    @Autowired
    private UserService userService;

    @Autowired
    private PreferenceService preferenceService;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
            Authentication authentication) throws IOException, ServletException 
    {
        User user = userService.findById(((UserDetails) authentication.getPrincipal()).getId());

        if (user.isMustChangePassword())
        {
            response.sendRedirect(request.getContextPath() + "/users/initialPasswordChange");
        }
        else
        {
            response.sendRedirect(request.getContextPath() + getAnchorPageURL(user));
        }
    }
}

Это отлично работает при входе в систему, поведение точно такое, как я хочу.На начальной странице смены пароля нет меню, но ничто не мешает пользователю изменить URL-адрес и перейти на домашнюю страницу без изменения своего пароля.В старые времена Spring MVC я бы создавал собственный класс Filter, работающий на каждой странице, который проверял бы, имеет ли пользователь, вошедший в систему, значение этого поля, равное true, и перенаправлял на начальную страницу смены пароля.Таким образом, весь сайт был бы недоступен, пока пароль не был изменен, независимо от того, что сделал пользователь.

Есть ли сегодня более элегантный способ Spring Security для этого?

Опять я предоставлю больше кода, если это может помочь, не хотел затоплять свой пост и хотелсначала включите самые важные биты.

1 Ответ

0 голосов
/ 03 июня 2019

Это работает в старом подходе Spring MVC Filter. Есть ли лучший, чистый способ Spring Security сделать это?

@Component
@WebFilter(urlPatterns = {"/*"}, description = "initialPasswordChangeFilter")
public class InitialPasswordChangeFilter implements Filter
{
    @Autowired
    private UserService userService;

    @Override
    public void init(FilterConfig fc) throws ServletException 
    {
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);

        Filter.super.init(fc);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException 
    {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;

        try
        {
            SecurityContextImpl sci = (SecurityContextImpl) req.getSession(false).getAttribute("SPRING_SECURITY_CONTEXT");

            User user = userService.findById(((UserDetails) sci.getAuthentication().getPrincipal()).getId());

            String url = req.getRequestURL().toString();

            if (user.isMustChangePassword() && !url.contains("initial") && !url.contains("/webjars") && !url.contains("/css") && 
                !url.contains("/js") && !url.contains("/images"))
            {
                res.sendRedirect(req.getContextPath() + "/users/initialPasswordChange");
            }
            else
            {
                chain.doFilter(request, response);
            }
        }
        catch (NullPointerException ex)
        {
            chain.doFilter(request, response);
        }
    }
}
...