Spring Security框架下简单实现远程用户限制IP地址内登录

    某些场景下,希望用户只能从限定的IP地址上登入系统,姑且勿论限定IP登录能带来多少安全性上的改善,我们来试试在使用Spring Security安全框架下,如何实现。

    有人肯定会提出一个方案,你看,简单,只要AuthenticationManager配置里,增加一个AuthenticationProvider就可以了,当然,这个是个很好的方案,也很容易实现,只要自定义AuthenticationProvider,在其authenticate方法里实现逻辑就可以了。而我在这里要说的是一种更为简单的办法,满足基本设计要求:

  • 在本地认证库里同时可配置IP限定规则

  • IP限定规则可以简单支持:单个IP;逗号,分号分割的多个IP;IP地址范围(同时支持多个定义)

  • 验证错误时抛出异常

    因为我采用的是本地库的认证,使用的是DaoAuthenticationProvider,且自定义了UserDetailsService,可以从UserDetailsService中读取出用户对应的限定IP配置,然后要做的是,我们继承DaoAuthenticationProvider自定义一个ExDaoAuthenticationProvider,重载其additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication)方法,进行IP范围check,如下为代码片段:

//省略imports
public class ExDaoAuthenticationProvider extends DaoAuthenticationProvider {
    // 框架MessageSource
    private MessageSourceAccessor exmessage = ExtrasMessageSource.getAccessor();

    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails,
            UsernamePasswordAuthenticationToken authentication)
            throws AuthenticationException {
        //执行父类里的检查
        super.additionalAuthenticationChecks(userDetails, authentication);
        //web,取得远程ip
        String remoteAddress = null;
        Object details = authentication.getDetails();
        if (details instanceof WebAuthenticationDetails) {
             WebAuthenticationDetails webDetails = (WebAuthenticationDetails) details;
             remoteAddress = webDetails.getRemoteAddress();
        }
        // 例行null检查远程ip,若空,可以直接返回或异常
        if (remoteAddress == null || remoteAddress.trim().length() == 0) {
                throw new BadCredentialsException(
                        exmessage
                                .getMessage("framework.security.notAuthorizedIp"));
        }
        String validAddress = null;
        // ... ... 取得限定IP设定,可以从UserDetails里读取或其他方法,省略......
        {validAddress = ... ...}
        //如果未限定ip,返回
        if (validAddress == null || validAddress.trim().length() == 0) {
            return;
        }
        
        //检查ip有效性
        if (!validateRemoteAddress(validAddress, remoteAddress)) {
            throw new BadCredentialsException(
                    exmessage.getMessage("framework.security.notAuthorizedIp"));
        }

    }

    private boolean validateRemoteAddress(String validAddress,
            String remoteAddress) {
        // 逗号,分号分割多个ip
        String[] address = validAddress.split(",|;");
        if (address != null && address.length > 0) {
            for (String addr : address) {
                if (match(addr, remoteAddress))
                    return true;
            }
        }
        return false;
    }

    private boolean match(String addr, String remoteAddress) {
        // 用各种正则表达式等验证IP有效性,省略... ...
        if (remoteAddress.matches(addr)) {
            return true;
        }
        ... ...
        // 围在有效IP里,则false
        return false;
    }
}

    最后,ExDaoAuthenticationProvider替换原配置,运行web应用,就可以完成对远程用户登录IP的限制了,非授权IP处登录,系统会抛出异常,界面显示给用户错误信息。

    通过上述办法,可以快速简单的实现基于本地认证库的IP限定逻辑,大家若有更好的实现方法,欢迎分享... ...


你可能感兴趣的:(spring,Security)