覆盖现有的 Spring Security 身份验证

Posted

技术标签:

【中文标题】覆盖现有的 Spring Security 身份验证【英文标题】:Override the existing Spring Security authentication 【发布时间】:2017-07-17 20:04:18 【问题描述】:

如何通过调用 Web 服务来,当它失败时,需要重定向一些第三方登录页面。

为了调用这个认证网络服务,我需要获取一些 ServletRequest 参数,为了重定向,我需要访问 ServletResponse。

因此我需要找出一些带有 ServletRequest 和 ServletResponse 参数的身份验证方法。

但是,我还是没有找到这样的 ProcessingFilter 或 AuthenticationProvider。

根据 Spring Security basic 看来我必须重写 AuthenticationProvider 相关的身份验证方法。

根据用例,我必须实现Spring Security Pre-authentication,

但问题是 PreAuthenticatedAuthenticationProvider 相关的“authenticate”方法只有 Authentication 参数。

PreAuthenticatedAuthenticationProvider

public class PreAuthenticatedAuthenticationProvider implements
        AuthenticationProvider, InitializingBean, Ordered 

    public Authentication authenticate(Authentication authentication) 


作为解决方案,是否有可能使用AuthenticationFailureHandler 的自定义实现?

谢谢。

【问题讨论】:

【参考方案1】:

我已经通过以下方式解决了这个问题,

实现自定义 AbstractPreAuthenticatedProcessingFilter

重写 doFilter 方法

@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException 

    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;

    try  

        // Get current Authentication object from SecurityContext
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();

        // Call for third party WS when the Authenticator object is null
        if (auth == null) 

            logger.debug("doFilter : Proceed the authentication"); 

            String appId = "My_APP_ID";
            String redirectURL = request.getRequestURL().toString(); 

            // Call for third party WS for get authenticate 
            if (WS_Authenticator.isAuthenticated(appId, redirectURL))  

                // Successfully authenticated
                logger.debug("doFilter : WS authentication success");

                // Get authenticated username 
                String userName = WS_Authenticator.getUserName();               

                // Put that username to request
                request.setAttribute("userName", userName);

             else 

                String redirectURL = WS_Authenticator.getAuthorizedURL();
                logger.debug("doFilter : WS authentication failed");
                logger.debug("doFilter : WS redirect URL : " + redirectURL);

                ((HttpServletResponse) response).setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
                ((HttpServletResponse) response).sendRedirect(redirectURL);

                // Return for bypass the filter chain 
                return;
               

         else 
            logger.debug("doFilter : Already authenticated"); 
           

     catch (Exception e) 
        logger.error("doFilter: " + e.getMessage());            
    

    super.doFilter(request, response, chain);
    return;

重写 getPreAuthenticatedCredentials 方法

@Override
protected Object getPreAuthenticatedCredentials(HttpServletRequest request) 

    // Get authenticated username
    String[] credentials = new String[1];
    credentials[0] = (String) request.getAttribute("userName");

    return credentials;

实现 CustomAuthenticationUserDetailsS​​erviceImpl

覆盖 loadUserDetails 方法

public class CustomAuthenticationUserDetailsServiceImpl implements AuthenticationUserDetailsService<Authentication> 

    protected static final Logger logger = Logger.getLogger(CustomAuthenticationUserDetailsServiceImpl.class);

    @Autowired
    private UserDataService userDataService;

    public UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException 

        // Get authenticated username 
        String[] credentials = (String[]) token.getCredentials();
        String userName = credentials[0];

        try 

            // Get user by username
            User user = userDataService.getDetailsByUserName(userName); 

            // Get authorities username             
            List<String> roles = userDataService.getRolesByUserName(userName);          
            user.setCustomerAuthorities(roles);
            return user;

         catch (Exception e) 
            logger.debug("loadUserDetails: User not found! " + e.getMessage());
            return null;
               
    

【讨论】:

以上是关于覆盖现有的 Spring Security 身份验证的主要内容,如果未能解决你的问题,请参考以下文章

使用 Spring Security 在一个应用程序中结合数据库和 SAML 身份验证

如何将 Spring Security 与我现有的 REST Web 服务集成

不使用 Spring Security 身份验证?

使用身份验证回退配置 Crowd Spring Security

Spring Security Active Directory LDAP 身份验证错误

如何在 Spring Security 中实现基于 JWT 的身份验证和授权