gpt4 book ai didi

java - Spring Security - 不是通过 IP 而是通过域/子域进行身份验证?

转载 作者:搜寻专家 更新时间:2023-11-01 01:27:14 24 4
gpt4 key购买 nike

我有一个基于 Spring 的 Web 服务,我想提供 Spring 安全性。它可以正常工作,并且可以通过 USER 和 ADMIN 角色进行身份验证。但是,我有一个新要求,我需要验证一个请求,而不是 USER 和 ADMIN 角色的请求,而是使用请求来自的子域。

一般是IP认证:

 <http use-expressions="true">
<intercept-url pattern="/admin*"
access="hasRole('admin') and hasIpAddress('192.168.1.0/24')"/>
...
</http>

但是,我的情况完全不同,我需要根据请求来自的域和子域进行身份验证。

喜欢:

jim.foo.com 
tim.foo.com

其中 jim.foo.com 和 tim.foo.com 具有相同的 IP 地址。每个子域都单独进行身份验证。

这可能吗?

最佳答案

根据@franz-ebner 在对@zayagi 的回答的评论中的要求,我可以在这里给出一个具体的完整示例。 @zayagi 的回答是一个完美的答案——这只是为了帮助其他人处理特定的用例。

这个例子是用 Java 8 编写的,当时 Spring Boot 是 1.1.6 和 Spring 4.0.x(Spring boot 现在是 1.3.0 和 Spring 4.2,其中包含 Web 配置改进)。这是在 2014 年底编写的,可能需要更新,但由于它是被请求的并且可能能够帮助其他人,所以按原样提供它。我无法提供测试,因为它们具有我不想共享的特定 IP 地址;-)

第一个类定义了 spring 安全表达式(例如 isCompanyInternal())并包括对 x-forwarded-for header 的支持。有了这个 header ,您不应该在所有情况下都信任它,因为它可以被任何人添加并且可能构成安全威胁。出于这个原因,只有某些内部 ip 范围受此 header 的信任。

    package org.mycompany.spring.security.web.acccess.expression;

import org.springframework.security.core.Authentication;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.expression.WebSecurityExpressionRoot;
import org.springframework.security.web.util.matcher.IpAddressMatcher;
import org.springframework.util.Assert;

import java.util.Optional;
import java.util.stream.Stream;

public class MyCompanyWebSecurityExpressionRoot extends WebSecurityExpressionRoot {
public static final String LOCALHOST = "127.0.0.1";

public static final String COMPANY_DESKTOPS = "-suppressed for example-";
public static final String COMPANY_INTERNET_1 = "-suppressed for example-";
public static final String COMPANY_INTERNET_2 = "-suppressed for example-";

/**
* See http://en.wikipedia.org/wiki/Private_network#Private_IPv4_address_spaces
*/
public static final String RFC_1918_INTERNAL_A = "10.0.0.0/8";
/**
* See http://en.wikipedia.org/wiki/Private_network#Private_IPv4_address_spaces
*/
public static final String RFC_1918_INTERNAL_B = "172.16.0.0/12";
/**
* See http://en.wikipedia.org/wiki/Private_network#Private_IPv4_address_spaces
*/
public static final String RFC_1918_INTERNAL_C = "192.168.0.0/16";


private IpAddressMatcher[] internalIpMatchers;
private IpAddressMatcher trustedProxyMatcher;

public MyCompanyWebSecurityExpressionRoot(Authentication a, FilterInvocation fi) {
super(a, fi);
setInternalIpRanges(RFC_1918_INTERNAL_A,
COMPANY_INTERNET_1,
COMPANY_INTERNET_2,
COMPANY_DESKTOPS,
RFC_1918_INTERNAL_B,
RFC_1918_INTERNAL_C,
LOCALHOST);
setTrustedProxyIpRange(RFC_1918_INTERNAL_A);
}

public boolean hasAnyIpAddress(String... ipAddresses) {
return Stream.of(ipAddresses)
.anyMatch(ipAddress -> new IpAddressMatcher(ipAddress).matches(request));
}

public boolean hasAnyIpAddressBehindProxy(String trustedProxyRange, String... ipAddresses) {
String remoteIpAddress = getForwardedIp(trustedProxyRange).orElseGet(request::getRemoteAddr);
return Stream.of(ipAddresses)
.anyMatch(ipAddress -> new IpAddressMatcher(ipAddress).matches(remoteIpAddress));
}

public boolean isCompanyInternal() {
String remoteIpAddress = getForwardedIp(trustedProxyMatcher).orElseGet(request::getRemoteAddr);
return Stream.of(internalIpMatchers)
.anyMatch(matcher -> matcher.matches(remoteIpAddress));
}

/**
* <p>This specifies one or more IP addresses/ranges that indicate the remote client is from the company network.</p>
*
* <p>If not set, this will default to all of the following values:</p>
* <ul>
* <li>{@code RFC_1918_INTERNAL_A}</li>
* <li>{@code RFC_1918_INTERNAL_B}</li>
* <li>{@code RFC_1918_INTERNAL_C}</li>
* <li>{@code COMPANY_INTERNET_1}</li>
* <li>{@code COMPANY_INTERNET_2}</li>
* <li>{@code COMPANY_DESKTOPS}</li>
* <li>{@code LOCALHOST}</li>
* </ul>
*
* @param internalIpRanges ip addresses or ranges. Must not be empty.
*
*/
public void setInternalIpRanges(String... internalIpRanges) {
Assert.notEmpty(internalIpRanges, "At least one IP address/range is required");
this.internalIpMatchers = Stream.of(internalIpRanges)
.map(IpAddressMatcher::new)
.toArray(IpAddressMatcher[]::new);
}

/**
* <p>When checking for the <code>x-forwarded-for</code> header in the incoming request we will only use
* that value from a trusted proxy as it can be spoofed by anyone. This value represents the IP address
* or IP range that we will trust.</p>
*
* <p>The default value if this is not set is {@code RFC_1918_INTERNAL_A}.</p>
*
* @param trustedProxyIpRange ip address or range. Must not be null.
*
*/
public void setTrustedProxyIpRange(String trustedProxyIpRange) {
Assert.notNull(trustedProxyIpRange, "A non-null value is for trusted proxy IP address/range");
this.trustedProxyMatcher = new IpAddressMatcher(trustedProxyIpRange);
}

private Optional<String> getForwardedIp(String trustedProxyRange) {
return getForwardedIp(new IpAddressMatcher(trustedProxyRange));
}

private Optional<String> getForwardedIp(IpAddressMatcher trustedProxyMatcher) {
String proxiedIp = request.getHeader("x-forwarded-for");
if (proxiedIp != null && trustedProxyMatcher.matches(request.getRemoteAddr())) {
return Optional.of(proxiedIp);
}
return Optional.empty();
}

}

第二个类定义了您在配置安全性时注入(inject)的表达式处理程序。

    package org.mycompany.spring.security.web.acccess.expression;

import org.springframework.security.access.expression.SecurityExpressionOperations;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;

public class MyCompanyWebSecurityExpressionHandler extends DefaultWebSecurityExpressionHandler {
private static final AuthenticationTrustResolver TRUST_RESOLVER = new AuthenticationTrustResolverImpl();

private String[] customInternalIpRanges;
private String customTrustedProxyIpRange;


@Override
protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) {
MyCompanyWebSecurityExpressionRoot root = new MyCompanyWebSecurityExpressionRoot(authentication, fi);
root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(TRUST_RESOLVER);
root.setRoleHierarchy(getRoleHierarchy());

if (customInternalIpRanges != null) {
root.setInternalIpRanges(customInternalIpRanges);
}
if (customTrustedProxyIpRange != null) {
root.setTrustedProxyIpRange(customTrustedProxyIpRange);
}

return root;
}

/**
* <p>Only set this if you want to override the default internal IP ranges defined within
* {@link MyCompanyWebSecurityExpressionRoot}.</p>
*
* <p>See {@link MyCompanyWebSecurityExpressionRoot#setInternalIpRanges(String...)}</p>
*
* @param customInternalIpRanges ip address or ranges
*/
public void setCustomInternalIpRanges(String... customInternalIpRanges) {
this.customInternalIpRanges = customInternalIpRanges;
}

/**
* Only set this if you want to override the default trusted proxy IP range set in
* {@link MyCompanyWebSecurityExpressionRoot}.
*
* @param customTrustedProxyIpRange ip address or range
*/
public void setCustomTrustedProxyIpRange(String customTrustedProxyIpRange) {
this.customTrustedProxyIpRange = customTrustedProxyIpRange;
}
}

最后是一起使用它们的示例: @配置 公共(public)静态类 WebInternalSecurityConfig 扩展 WebSecurityConfigurerAdapter {

        @Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/favicon.ico", "/robots.txt");
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.expressionHandler(new MyCompanyWebSecurityExpressionHandler())
.anyRequest().access("isCompanyInternal()");
}
}

关于java - Spring Security - 不是通过 IP 而是通过域/子域进行身份验证?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16104172/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com