Spring security:如果用户不满足特定条件,则使每个页面重定向

Posted

技术标签:

【中文标题】Spring security:如果用户不满足特定条件,则使每个页面重定向【英文标题】:Spring security : make every page redirect if the user doesn't meet a specific criteria 【发布时间】:2019-10-19 07:24:37 【问题描述】:

我正在开发一个使用 Spring Security 作为身份验证/授权提供程序的 Web 应用程序。这是我的配置方式:

@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 和 UserDetailsS​​ervice 的扩展来在 Spring Security 和 DB 之间进行交互。在我的用户实体中,我有一个布尔字段来控制用户是否需要更改他的密码(首次登录)。为了在用户登录时实现此功能,我有以下 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 时代,我会构建一个在每个页面上运行的自定义过滤器类,该类会检查登录的用户是否将该字段设置为 true 并重定向到初始密码更改页面。这样,无论用户做什么,在更改密码之前,整个站点都将无法访问。

现在有没有更优雅的 Spring Security 方式来做到这一点?

再次,如果有帮助,我将提供更多代码,不想淹没我的帖子,并希望首先包含最相关的部分。

【问题讨论】:

【参考方案1】:

这适用于旧的 Spring MVC 过滤器方法。有没有更好、更纯粹的 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);
        
    

【讨论】:

以上是关于Spring security:如果用户不满足特定条件,则使每个页面重定向的主要内容,如果未能解决你的问题,请参考以下文章

Grails Spring Security 查询没有特定角色的用户

spring security拦截url角色

Spring Security with Spring Boot:使用过滤器时允许未经身份验证的用户访问特定端点

如果用户先前已授权访问,如何绕过 Spring security OAuth2 中的访问确认步骤?

如何使用 Spring Security 处理基于用户权限的授权?

认证后转到特定的jsp页面(spring security)