java 在 Spring 3.1 中通过 IP 地址进行身份验证:最聪明的方法来做到这一点?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10147161/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 23:48:07  来源:igfitidea点击:

Authenticating By IP Address In Spring 3.1: Smartest Way To Do That?

javaauthenticationspring-securityip

提问by Steve

I've implemented LDAP authentication using Spring Security 3.1. My security.xml file for that is posted below.

我已经使用 Spring Security 3.1 实现了 LDAP 身份验证。我的 security.xml 文件发布在下面。

I need to alter my authentication process such that if a user comes to the site from an IP Address on a "white list" ( kept in a database table ), then that user should automatically be authenticated with Spring 3.1 and then redirected away from the login screen( not my idea, I was told to so).

我需要更改我的身份验证过程,以便如果用户从“白名单”(保存在数据库表中)上的 IP 地址访问该站点,则该用户应自动通过 Spring 3.1 进行身份验证,然后重定向离开登录屏幕(不是我的主意,有人告诉我是这样)。

If the user is not from one of the white listed IP Addresses, then s/he should be forced to go through the LDAP authentication on the login page.

如果用户不是来自列入白名单的 IP 地址之一,那么他/她应该被强制通过登录页面上的 LDAP 身份验证。

I'm new to Spring and Spring Security so I went to the Spring 3.1 Reference Documentationand read all of Section I. There, I read the advice that if you have any special authentication needs you should read Section II Architecture and Implementation. I did that, very slowly and took notes.

我是 Spring 和 Spring Security 的新手,所以我去了Spring 3.1 参考文档并阅读了第一部分的所有内容。在那里,我阅读了建议,如果您有任何特殊的身份验证需求,您应该阅读 第二部分架构和实现。我这样做了,非常缓慢,并记下了笔记。

However, since I am new to all of this I'm not sure I completely understand what I need to do and what is the smartest way of going about doing it.

但是,由于我对所有这些都不熟悉,因此我不确定我是否完全理解我需要做什么以及最明智的做法是什么。



Update 3: I got the skeleton code to work, here are the files I ended up with

更新 3:我得到了框架代码,这是我最终得到的文件



My custom AuthenticationProvider implementation for authenticating by IP Address

我的自定义 AuthenticationProvider 实现,用于通过 IP 地址进行身份验证

// Authentication Provider To Authenticate By IP Address With Allowed IPs
// Stored in a db table


package acme.com.controller.security;

//import acme.com.controller.security.CustomUserInfoHolder;

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;

import org.apache.log4j.Logger;


public class CustomIPAddressAuthenticationProvider implements AuthenticationProvider
{

    private static final Logger logger = Logger.getLogger(CustomIPAddressAuthenticationProvider.class);
    private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();


    @Override
    public Authentication authenticate(Authentication authentication)
    throws AuthenticationException {


        WebAuthenticationDetails wad = null;
        String userIPAddress         = null;
        boolean isAuthenticatedByIP  = false;

        // Get the IP address of the user tyring to use the site
        wad = (WebAuthenticationDetails) authentication.getDetails();
        userIPAddress = wad.getRemoteAddress();


        logger.debug("userIPAddress == " + userIPAddress);

        // Compare the user's IP Address with the IP address in the database
        // stored in the USERS_AUTHENTICATED_BY_IP table & joined to the
        // USERS tabe to make sure the IP Address has a current user
        //isAuthenticatedByIP =  someDataObject.hasIPAddress(userIPAddress);
        isAuthenticatedByIP = true;


        // Authenticated, the user's IP address matches one in the database
        if (isAuthenticatedByIP)
        {

            logger.debug("isAuthenticatedByIP is true, IP Addresses match");
            UserDetails user = null;


            UsernamePasswordAuthenticationToken result = null;

            result = new UsernamePasswordAuthenticationToken("John Principal",
                                                              "PlaceholderPWE"); 

            result.setDetails(authentication.getDetails());

            return result;
        }


        // Authentication didn't happen, return null to signal that the 
        // AuthenticationManager should move on to the next Authentication provider
        return null;
    }


    @Override
    public boolean supports(Class<? extends Object> authentication)
    {
        // copied it from AbstractUserDetailsAuthenticationProvider
        return(UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
    }

}

My *-security.xml file

我的 *-security.xml 文件

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:s="http://www.springframework.org/schema/security"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <s:http pattern="/login*" security="none"/>
    <s:http pattern="/search*" security="none"/>
    <s:http pattern="/css/**" security="none"/>
    <s:http pattern="/js/**" security="none"/>
    <s:http pattern="/images/**" security="none"/>




    <s:http auto-config="true" use-expressions="true">
        <s:intercept-url pattern="/**" access="isAuthenticated()" />

        <s:form-login login-page="/login"
          authentication-failure-url="/loginfailed" />
        <s:logout logout-success-url="/logout" />
    </s:http>



    <s:ldap-server url = "ldap://ldap-itc.smen.acme.com:636/o=acme.com"/>


    <bean id="customIPAddressAuthenticationProvider" class="com.acme.controller.security.CustomIPAddressAuthenticationProvider" />


    <s:authentication-manager>
        <!-- Proposed: Custom Authentication Provider: Try To Authenticate BY IP Address First, IF NOT, Authenticate WiTh THE LDAP Authentication Provider -->
        <s:authentication-provider ref="customIPAddressAuthenticationProvider" />
        <s:ldap-authentication-provider user-dn-pattern="uid={0},ou=People"/>
    </s:authentication-manager>


</beans>

采纳答案by Vasily Tokarov

Your approach seems pretty sound, you are right in thinking that Spring will try each AuthenticationProvider until it gets a successful result, so in your case you would define your IP based provider before the LDAP provider.

您的方法看起来很合理,您认为 Spring 将尝试每个 AuthenticationProvider 直到获得成功结果是正确的,因此在您的情况下,您将在 LDAP 提供程序之前定义基于 IP 的提供程序。

Depending on your setup you may not get a WebAuthenticationDetails object on your authentication.getDetails() call. If this is the case you should add Spring's RequestContextListeneror RequestContextFilterto your web.xml. You will then be able to get the source IP address by using the RequestContextHolder class and calling RequestContextHolder.getRequestAttributes().

根据您的设置,您可能不会在 authentication.getDetails() 调用中获得 WebAuthenticationDetails 对象。如果是这种情况,您应该将 Spring 的RequestContextListenerRequestContextFilter添加到您的 web.xml。然后,您将能够通过使用 RequestContextHolder 类并调用 RequestContextHolder.getRequestAttributes() 来获取源 IP 地址。

You should only need to implement an AuthenticationProvider, there is no need to implement a UserDetailsService, UserDetails or Authentication class. You should return null if you are not able to authenticate the user via his IP address. In this case Spring will try the LDAP provider. If for some reason you do not want to pass the attempt onto LDAP you should throw an AuthenticationException which will stop the process and ultimately result in a 403 error for the user.

您应该只需要实现一个 AuthenticationProvider,不需要实现 UserDetailsS​​ervice、UserDetails 或 Authentication 类。如果您无法通过用户的 IP 地址对用户进行身份验证,则应返回 null。在这种情况下,Spring 将尝试使用 LDAP 提供程序。如果由于某种原因您不想将尝试传递给 LDAP,您应该抛出一个 AuthenticationException ,这将停止该过程并最终导致用户出现 403 错误。

I hope this helps :)

我希望这有帮助 :)