You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Spring Boot应用端点仅对物理在场/SSH授权用户开放的实现问询

嘿,这个需求结合了身份认证和环境校验,挺贴合运维场景的,我给你几个在Spring Boot里能落地的技术方案,都是基于Spring Security生态的,上手不难:

方案1:IP白名单 + Spring Security 基础授权(满足“物理位于服务器所在系统”的场景)

这个方案核心是先限制请求来源的IP范围,再结合用户身份认证,确保只有内网/本机的授权用户能访问端点。

  • 步骤1:配置IP白名单
    在Spring Security的配置类里,添加IP地址的校验规则,比如允许服务器本机(127.0.0.1localhost)、服务器所在局域网的IP段(比如192.168.1.0/24):

    @Configuration
    @EnableWebSecurity
    public class SecurityConfig {
        @Bean
        public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
            http
                .authorizeHttpRequests(auth -> auth
                    .requestMatchers("/your-protected-endpoint/**")
                    .access("hasAuthority('ROLE_AUTHORIZED_USER') and (hasIpAddress('127.0.0.1/32') or hasIpAddress('192.168.1.0/24'))")
                    .anyRequest().permitAll()
                )
                .formLogin(Customizer.withDefaults()) // 替换成你实际用的认证方式,比如JWT、OAuth2
                .csrf(csrf -> csrf.disable()); // 根据业务场景决定是否关闭CSRF
            return http.build();
        }
    }
    

    这里的hasIpAddress是Spring Security自带的表达式,能直接校验请求的来源IP。

  • 步骤2:用户授权配置
    确保你的用户体系里给授权用户分配ROLE_AUTHORIZED_USER权限,不管是从数据库读取还是测试阶段硬编码,都要和上面的表达式对应上。

方案2:SSH权限校验(满足“拥有服务器SSH访问权限”的场景)

这个方案需要验证请求用户是否持有服务器的SSH授权密钥,或者能通过服务器的SSH身份校验,这里有两种实现思路:

思路A:校验用户SSH公钥是否在服务器authorized_keys

让用户在请求时携带自己的SSH公钥内容,后端读取服务器上的~/.ssh/authorized_keys文件,检查该公钥是否存在:

@Component
public class SshPermissionValidator {
    private static final String AUTHORIZED_KEYS_PATH = System.getProperty("user.home") + "/.ssh/authorized_keys";

    public boolean hasSshAccess(String userPublicKey) throws IOException {
        List<String> authorizedKeys = Files.readAllLines(Paths.get(AUTHORIZED_KEYS_PATH));
        // 清理公钥格式,只取核心密钥部分(去掉前缀、注释)
        String cleanedUserKey = userPublicKey.trim().split(" ")[1];
        return authorizedKeys.stream()
                .map(key -> key.trim().split(" ")[1])
                .anyMatch(cleanedUserKey::equals);
    }
}

然后在Spring Security里自定义权限表达式,把这个校验逻辑加进去:

@Configuration
public class SecurityExpressionConfig extends DefaultWebSecurityExpressionHandler {
    @Autowired
    private SshPermissionValidator sshValidator;

    @Override
    protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) {
        WebSecurityExpressionRoot root = (WebSecurityExpressionRoot) super.createSecurityExpressionRoot(authentication, fi);
        root.setPermissionEvaluator(new PermissionEvaluator() {
            @Override
            public boolean hasPermission(Authentication auth, Object targetDomainObject, Object permission) {
                if ("SSH_ACCESS".equals(permission)) {
                    // 从请求Header里获取用户的SSH公钥
                    String userPublicKey = fi.getHttpRequest().getHeader("X-SSH-Public-Key");
                    try {
                        return sshValidator.hasSshAccess(userPublicKey);
                    } catch (IOException e) {
                        return false;
                    }
                }
                return false;
            }

            @Override
            public boolean hasPermission(Authentication auth, Serializable targetId, String targetType, Object permission) {
                return false;
            }
        });
        return root;
    }
}

之后在Security配置里修改访问规则,把SSH校验和IP校验做或逻辑:

.requestMatchers("/your-protected-endpoint/**")
.access("hasAuthority('ROLE_AUTHORIZED_USER') and (hasIpAddress('127.0.0.1/32') or hasIpAddress('192.168.1.0/24') or hasPermission(null, 'SSH_ACCESS'))")

思路B:基于本地SSH会话校验(仅适用于服务器本机访问场景)

如果用户是通过SSH登录服务器后再访问应用,可以检查请求的环境变量是否包含SSH_AUTH_SOCK(SSH代理套接字路径),或者通过执行系统命令whoami确认当前用户是否在SSH授权列表中。不过这种方式只适合本机会话访问,远程SSH转发的场景需要额外处理。

方案3:本地密钥文件校验(你提到的“借助密钥解锁端点”思路)

这个方案是在服务器上存放一个只有授权用户能获取的密钥文件,用户请求时携带密钥内容,后端读取本地文件做对比:

  • 步骤1:生成本地密钥文件
    在服务器上生成一个随机密钥,并设置严格的访问权限:

    openssl rand -hex 32 > /opt/app/secure/endpoint.key
    chmod 600 /opt/app/secure/endpoint.key # 确保只有应用进程能读取
    
  • 步骤2:后端校验逻辑

    @Component
    public class LocalKeyValidator {
        private static final String KEY_FILE_PATH = "/opt/app/secure/endpoint.key";
        private String validKey;
    
        @PostConstruct
        public void loadValidKey() throws IOException {
            this.validKey = Files.readString(Paths.get(KEY_FILE_PATH)).trim();
        }
    
        public boolean isValidKey(String providedKey) {
            return validKey.equals(providedKey.trim());
        }
    }
    

    同样在Spring Security里自定义表达式,把这个校验加入访问规则,和前面的IP、SSH校验组合使用。

方案对比与注意事项
  • IP白名单方案:简单易维护,适合内网场景,但要注意如果服务器有公网IP,需结合反向代理传递真实IP(比如Nginx的X-Forwarded-For),避免IP伪造。
  • SSH权限方案:贴合运维人员使用习惯,安全性高,但需要用户配合提供公钥,且依赖服务器的SSH配置。
  • 本地密钥方案:实现最直接,但密钥需妥善保管,定期轮换,避免泄露。

最后要强调:所有方案都必须先做用户身份认证(比如JWT、OAuth2),再做环境/权限的二次校验,不要跳过身份认证直接用IP或密钥校验,否则容易被绕过。

内容的提问来源于stack exchange,提问作者Sayak Mukhopadhyay

火山引擎 最新活动