java连接kerberos用户认证以及java连接ldap读取账户信息

news2024/10/24 6:27:18

在这里插入图片描述

文章目录

  • 一、背景
  • 二、代码
    • 2.1目录
    • 2.2配置文件application.properties
    • 2.3pom依赖
    • 2.4代码
      • AuthProviderConfig配置类
      • CustomConfigurationByKeytab配置类
      • CustomConfigurationByPassword配置类
      • LdapConfiguration配置类
      • TestController
      • LdapUser实体类
      • MyCallbackHandler
      • LdapUserAttributeMapper映射类
      • DummyUserDetailsService实现类
      • LdapTest2Application启动类
      • KerberosTest测试类
      • LdapTest测试类
      • SpringVersionUtils测试类
  • 三、可能碰到的报错
    • 错误场景1:javax.security.auth.login.LoginException: Receive timed out
    • 错误场景2:javax.security.auth.login.LoginException: Cannot locate KDC

一、背景

亲测可用,之前搜索了很多博客,啥样的都有,就是不介绍报错以及配置用处,根本不懂照抄那些配置是干啥的,稀里糊涂的按照博客搭完也跑不起来,因此记录这个。

项目背景:公司项目当前采用http协议+shiro+mysql的登录认证方式,而现在想支持ldap协议认证登录然后能够访问自己公司的项目网站。

举例说明:假设我们公司有自己的门户网站,现在我们收购了一家公司,他们数据库采用ldap存储用户数据,那么为了他们账户能登陆我们公司项目所以需要集成,而不是再把他们的账户重新在mysql再创建一遍,万一人家有1W个账户呢,不累死了且也不现实啊。

需要安装openldap+kerberos,且ldap和kerberos安装在同一台服务器上,当前版本如下:

  • centos 7.9
  • openldap 2.4.44
  • phpldapadmin 1.2.5
  • 服务器IP:10.110.38.162
  • Kerberos :Kerberos 5 release 1.15.1

另外介绍下我的Spring各个版本:

  • Spring Security:4.2.3.RELEASE
  • Spring Version:4.3.9.RELEASE
  • SpringBoot Version:1.4.7.RELEASE

注意点1:我之所以选这么旧的版本,是因为我最后要在自己项目集成,我们项目就是上面版本附近的,所以不能选太高版本,这点请注意各版本之间的兼容性问题。
注意点2:如果里面的某些配置不知道在哪或者不知道干啥的,可以看我的前面的博客,详细介绍了安装配置等,可以大致了解参数。

二、代码

2.1目录

在这里插入图片描述

2.2配置文件application.properties

server.port=8020

server.ldap.urls=ldap://10.110.38.162:389
server.ldap.username=cn=admin,dc=node3,dc=com
server.ldap.password=123456
server.ldap.base=dc=node3,dc=com
server.app.ad-domain=NODE3.COM

2.3pom依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>1.4.7.RELEASE</version>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>ldap-test2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>ldap-test2</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--解决@RestController注解爆红-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
        <!--测试类-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-security-core</artifactId>
                    <groupId>org.springframework.security</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-ldap</artifactId>
            <version>2.6.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-ldap</artifactId>
            <version>2.6.3</version>
        </dependency>
        <dependency>
            <groupId>com.sun</groupId>
            <artifactId>ldapbp</artifactId>
            <version>1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.ldap</groupId>
            <artifactId>spring-ldap-core</artifactId>
            <version>2.4.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.directory.api</groupId>
            <artifactId>api-all</artifactId>
            <version>2.0.0</version>
        </dependency>

        <!-- Spring Security Kerberos -->
        <dependency>
            <groupId>org.springframework.security.kerberos</groupId>
            <artifactId>spring-security-kerberos-core</artifactId>
            <version>1.0.1.RELEASE</version>
            <exclusions>
                <exclusion>
                    <artifactId>spring-security-core</artifactId>
                    <groupId>org.springframework.security</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.kerberos</groupId>
            <artifactId>spring-security-kerberos-client</artifactId>
            <version>1.0.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.kerberos</groupId>
            <artifactId>spring-security-kerberos-web</artifactId>
            <version>1.0.1.RELEASE</version>
        </dependency>

        <!-- Additional dependencies for Spring LDAP and Security -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-ldap</artifactId>
            <version>4.2.3.RELEASE</version>
            <exclusions>
                <exclusion>
                    <artifactId>spring-security-core</artifactId>
                    <groupId>org.springframework.security</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
            <version>4.2.3.RELEASE</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.example.ldaptest2.LdapTest2Application</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2.4代码

AuthProviderConfig配置类

package com.example.ldaptest2.config;

import com.example.ldaptest2.service.DummyUserDetailsService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
import org.springframework.security.kerberos.authentication.KerberosAuthenticationProvider;
import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosClient;

@Configuration
@EnableWebMvcSecurity
public class AuthProviderConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/ldap/*").permitAll()
            .anyRequest().authenticated();
//            .and()
//            .formLogin()
//            .loginPage("/login").permitAll()
//            .and()
//            .logout()
//            .permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(kerberosAuthenticationProvider());
    }

    @Bean
    public KerberosAuthenticationProvider kerberosAuthenticationProvider() {
        KerberosAuthenticationProvider provider = new KerberosAuthenticationProvider();
        SunJaasKerberosClient client = new SunJaasKerberosClient();
        client.setDebug(true);
        provider.setKerberosClient(client);
        provider.setUserDetailsService(dummyUserDetailsService());
        return provider;
    }

    @Bean
    public DummyUserDetailsService dummyUserDetailsService() {
        return new DummyUserDetailsService();
    }

}

CustomConfigurationByKeytab配置类

package com.example.ldaptest2.config;

import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author 211145187
 * @Date 2024/6/13 16:34
 **/
// 自定义 Configuration 类,用于提供 Kerberos 登录配置
public class CustomConfigurationByKeytab extends Configuration {
    @Override
    public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
        if ("KrbLogin".equals(name)) {
            Map<String, String> options = new HashMap<>();
            options.put("useKeyTab", "true");   //指定是否使用 keytab 文件进行登录,这里设置为 true,表示使用 keytab 文件。
            options.put("keyTab", "C:\\Users\\211145187\\Desktop\\fsdownload\\ldap.keytab"); //指定 keytab 文件的路径,这里设置为 "/etc/openldap/ldap.keytab"。
//            options.put("keyTab", "/etc/openldap/ldap.keytab"); //指定 keytab 文件的路径,这里设置为 "/etc/openldap/ldap.keytab"。
            options.put("storeKey", "true");    //指定是否将密钥存储在 Subject 中,这里设置为 true,表示存储密钥。
            options.put("useTicketCache", "false"); //指定是否使用票据缓存,这里设置为 false,表示不使用票据缓存。
            options.put("doNotPrompt", "true"); //指定是否禁止提示用户输入用户名和密码,这里设置为 true,表示禁止提示。
            options.put("debug", "true");   //指定是否启用调试模式,这里设置为 true,表示启用调试模式。
            options.put("principal", "ldapadmin@NODE3.COM"); //指定要使用的主体名称,这里设置为 "ldap/bridge1@NODE3.COM",表示使用的服务主体。

            // 定义 Kerberos 登录模块的配置项
            AppConfigurationEntry entry = new AppConfigurationEntry(
                    "com.sun.security.auth.module.Krb5LoginModule",
                    AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
                    options
            );
            return new AppConfigurationEntry[]{entry};
        }
        return null;
    }
}

CustomConfigurationByPassword配置类

package com.example.ldaptest2.config;

import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author 211145187
 * @Date 2024/6/13 16:34
 **/
// 自定义 Configuration 类,用于提供 Kerberos 登录配置
public class CustomConfigurationByPassword extends Configuration {
    @Override
    public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
        if ("KrbLogin".equals(name)) {
            Map<String, String> options = new HashMap<>();
            options.put("useKeyTab", "false");   //指定是否使用 keytab 文件进行登录,这里设置为 true,表示使用 keytab 文件。
            options.put("storeKey", "true");    //指定是否将密钥存储在 Subject 中,这里设置为 true,表示存储密钥。
            options.put("useTicketCache", "false"); //指定是否使用票据缓存,这里设置为 false,表示不使用票据缓存。
            options.put("doNotPrompt", "false"); //指定是否禁止提示用户输入用户名和密码,这里设置为 true,表示禁止提示。
            options.put("debug", "true");   //指定是否启用调试模式,这里设置为 true,表示启用调试模式。
            options.put("password", "123456"); //指定要使用的主体名称,这里设置为 "ldap/bridge1@NODE3.COM",表示使用的服务主体。
            options.put("principal", "testldap3@NODE3.COM"); //指定要使用的主体名称,这里设置为 "ldap/bridge1@NODE3.COM",表示使用的服务主体。

            // 定义 Kerberos 登录模块的配置项
            AppConfigurationEntry entry = new AppConfigurationEntry(
                    "com.sun.security.auth.module.Krb5LoginModule",
                    AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
                    options
            );
            return new AppConfigurationEntry[]{entry};
        }
        return null;
    }
}

LdapConfiguration配置类

package com.example.ldaptest2.config;//package com.ldap.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;


/**
 * LDAP 的自动配置类
 * @Author 211145187
 * @Date 2024/5/21 16:44
 **/
@Configuration
public class LdapConfiguration {
    private static Logger logger = LoggerFactory.getLogger(LdapConfiguration.class);

    private LdapTemplate ldapTemplate;
    @Value("${server.ldap.urls}")
    private String adServer;
    @Value("${server.ldap.username}")
    private String username;
    @Value("${server.ldap.password}")
    private String password;
    @Value("${server.ldap.base}")
    private String ldapSearchBase;

    @Bean
    public LdapContextSource contextSource() {
        LdapContextSource contextSource = new LdapContextSource();
        Map<String, Object> config = new HashMap();
        contextSource.setUrl(adServer);
        contextSource.setBase(ldapSearchBase);
        contextSource.setUserDn(username);
        contextSource.setPassword(password);
        //  解决 乱码 的关键一句
        config.put("java.naming.ldap.attributes.binary", "objectGUID");
        contextSource.setPooled(true);
        contextSource.setBaseEnvironmentProperties(config);
        return contextSource;

    }

    @Bean
    public LdapTemplate ldapTemplate(LdapContextSource contextSource) {
        if (Objects.isNull(contextSource)) {
            throw new RuntimeException("ldap contextSource error");
        }
        if (null == ldapTemplate) {
            ldapTemplate = new LdapTemplate(contextSource);
        }
        return ldapTemplate;
    }

}

TestController

注意:其实这个controller可有可无,因为你写java客户端连接kerberos,如果不涉及打包部署linux环境通过url方式掉方法,完全可以不写这个,只写本地测试方法即可。

package com.example.ldaptest2.controller;

import com.example.ldaptest2.config.CustomConfigurationByKeytab;
import com.example.ldaptest2.config.CustomConfigurationByPassword;
import com.example.ldaptest2.entity.LdapUser;
import com.example.ldaptest2.entity.MyCallbackHandler;
import com.example.ldaptest2.mapper.LdapUserAttributeMapper;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;

/**
 * @Author 211145187
 * @Date 2024/6/14 17:18
 **/
@RestController
@RequestMapping("/ldap")
public class TestController {
    private static Logger logger = LoggerFactory.getLogger(TestController.class);
    @Autowired
    private LdapTemplate ldapTemplate;

    //keytab认证
    @GetMapping(value = "/authenticateUserByKeytab")
    public void authenticateUserByKeytab() {
        try {
            System.setProperty("java.security.krb5.conf", "/etc/krb5.conf");
            // 创建 LoginContext 对象,并为其提供自定义 Configuration
            LoginContext lc = new LoginContext("KrbLogin", null, null, new CustomConfigurationByKeytab());

            // 进行 Kerberos 认证
            lc.login();
            // 获取 Subject
            Subject subject = lc.getSubject();
//            logger.info("subject:{}", subject);
            // 在这里可以使用 subject 来执行进一步的操作,如访问受限资源
            // 登出
            lc.logout();
        } catch (LoginException e) {
            // 处理登录异常
            e.printStackTrace();
            logger.error("LoginException e:{}", e.getMessage());
        }
    }

    //用户+密码认证
    @GetMapping(value = "/authenticateUserByPassword")
    public void authenticateUserByPassword() {
        try {
            System.setProperty("java.security.krb5.conf", "/etc/krb5.conf");
            // 创建 LoginContext 对象,并为其提供自定义 Configuration
            LoginContext lc = new LoginContext("KrbLogin", null, new MyCallbackHandler(), new CustomConfigurationByPassword());

            // 进行 Kerberos 认证
            lc.login();
            // 获取 Subject
            Subject subject = lc.getSubject();
//            logger.info("subject:{}", subject);
            // 在这里可以使用 subject 来执行进一步的操作,如访问受限资源
            // 登出
            lc.logout();
        } catch (LoginException e) {
            // 处理登录异常
            e.printStackTrace();
            logger.error("LoginException e:{}", e.getMessage());
        }
    }

    @GetMapping(value = "/test")
    public String test() {
        return "Hello";
    }


    //直接连接ldap的,这是不安全的,未加密,都是铭文
    @GetMapping(value = "/listUsers")
    public void listUsers() throws NoSuchAlgorithmException {
        AndFilter filter = new AndFilter();
        filter.and(new EqualsFilter("objectClass", "inetOrgPerson"));

        List<LdapUser> users = ldapTemplate.search("ou=People,dc=hdp", filter.encode(), new LdapUserAttributeMapper());
        for (LdapUser user: users ) {
            System.out.println("user: " + user);
            System.out.println("userPassword:" + user.getUserPassword());
            System.out.println(verifySHA(user.getUserPassword(), "123456"));
        }
    }

    @SuppressWarnings(value = "unchecked")
    public static boolean verifySHA(String ldappw, String inputpw) throws NoSuchAlgorithmException {

        // MessageDigest 提供了消息摘要算法,如 MD5 或 SHA,的功能,这里LDAP使用的是SHA-1
        MessageDigest md = MessageDigest.getInstance("SHA-1");

        // 取出加密字符
        if (ldappw.startsWith("{SSHA}")) {
            ldappw = ldappw.substring(6);
        } else if (ldappw.startsWith("{SHA}")) {
            ldappw = ldappw.substring(5);
        }

        // 解码BASE64
        byte[] ldappwbyte = Base64.decode(ldappw);
        byte[] shacode;
        byte[] salt;

        // 前20位是SHA-1加密段,20位后是最初加密时的随机明文
        if (ldappwbyte.length <= 20) {
            shacode = ldappwbyte;
            salt = new byte[0];
        } else {
            shacode = new byte[20];
            salt = new byte[ldappwbyte.length - 20];
            System.arraycopy(ldappwbyte, 0, shacode, 0, 20);
            System.arraycopy(ldappwbyte, 20, salt, 0, salt.length);
        }

        // 把用户输入的密码添加到摘要计算信息
        md.update(inputpw.getBytes());
        // 把随机明文添加到摘要计算信息
        md.update(salt);

        // 按SSHA把当前用户密码进行计算
        byte[] inputpwbyte = md.digest();

        // 返回校验结果
        return MessageDigest.isEqual(shacode, inputpwbyte);
    }
}

LdapUser实体类

package com.example.ldaptest2.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author 211145187
 * @Date 2024/5/22 09:31
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LdapUser {
    private String uid;

    private String dn;

    private String cn;

    private String sn;

    private String userPassword;
}

MyCallbackHandler

package com.example.ldaptest2.entity;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;

/**
 * @Author 211145187
 * @Date 2024/6/13 19:18
 **/
public class MyCallbackHandler implements CallbackHandler {
    @Override
    public void handle(Callback[] callbacks) throws UnsupportedCallbackException {
        for (Callback callback : callbacks) {
            if (callback instanceof NameCallback) {
                // 处理用户名回调
                NameCallback nc = (NameCallback) callback;
                nc.setName("ldapadmin@NODE3.COM"); // 设置用户名
            } else if (callback instanceof PasswordCallback) {
                // 处理密码回调
                PasswordCallback pc = (PasswordCallback) callback;
                pc.setPassword("123456".toCharArray()); // 设置密码
            } else {
                throw new UnsupportedCallbackException(callback, "Unrecognized Callback");
                // 其他类型的回调
                // 可以根据需要处理其他类型的回调
            }
        }
    }
}

LdapUserAttributeMapper映射类

package com.example.ldaptest2.mapper;

import com.example.ldaptest2.entity.LdapUser;
import org.springframework.ldap.core.AttributesMapper;

import javax.naming.NamingException;
import javax.naming.directory.Attributes;

/**
 * 将ldap返回的结果,转成指定对象
 */
public class LdapUserAttributeMapper implements AttributesMapper {

    /**
     * 将单个Attributes转成单个对象
     * @param attrs
     * @return
     * @throws NamingException
     */
    @Override
    public Object mapFromAttributes(Attributes attrs) throws NamingException {
        LdapUser user  = new LdapUser();

        if(attrs.get("uid") != null){
            user.setUid( attrs.get("uid").get().toString());
        }
        if(attrs.get("cn") != null){
            user.setCn( attrs.get("cn").get().toString());
        }
        if(attrs.get("dn") != null){
            user.setDn( attrs.get("dn").get().toString());
        }
        if(attrs.get("sn") != null){
            user.setSn( attrs.get("sn").get().toString());
        }
        if(attrs.get("userPassword") != null){
            user.setUserPassword(new String((byte[])attrs.get("userPassword").get()));
        }
        return user;
    }
}


DummyUserDetailsService实现类

package com.example.ldaptest2.service;

import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

/**
 * @Author 211145187
 * @Date 2024/6/13 15:37
 **/
public class DummyUserDetailsService implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return new User(username, "notUsed", true, true, true, true,
                AuthorityUtils.createAuthorityList("ROLE_USER"));
    }

}

LdapTest2Application启动类

package com.example.ldaptest2;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class LdapTest2Application {

    public static void main(String[] args) {
        SpringApplication.run(LdapTest2Application.class, args);
    }
}

KerberosTest测试类

package com.example.ldaptest2;

import com.example.ldaptest2.config.CustomConfigurationByKeytab;
import com.example.ldaptest2.config.CustomConfigurationByPassword;
import com.example.ldaptest2.entity.MyCallbackHandler;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;

@SpringBootTest
@RunWith(SpringRunner.class)
public class KerberosTest {
    private static Logger logger = LoggerFactory.getLogger(KerberosTest.class);

    //用户+密码认证
    @Test
    public void authenticateUserByPassword() {
        try {
            System.setProperty("java.security.krb5.conf", "C:\\Users\\211145187\\Desktop\\fsdownload\\krb5.conf");
            // 创建 LoginContext 对象,并为其提供自定义 Configuration
            LoginContext lc = new LoginContext("KrbLogin", null, new MyCallbackHandler(), new CustomConfigurationByPassword());

            // 进行 Kerberos 认证
            lc.login();
            // 获取 Subject
            Subject subject = lc.getSubject();
//            logger.info("subject:{}", subject);
            // 在这里可以使用 subject 来执行进一步的操作,如访问受限资源
            // 登出
            lc.logout();
        } catch (LoginException e) {
            // 处理登录异常
            e.printStackTrace();
        }
    }

    //keytab认证
    @Test
    public void authenticateUserByKeytab() {
        try {
            System.setProperty("java.security.krb5.conf", "C:\\Users\\211145187\\Desktop\\fsdownload\\krb5.conf");
            // 创建 LoginContext 对象,并为其提供自定义 Configuration
            LoginContext lc = new LoginContext("KrbLogin", null, null, new CustomConfigurationByKeytab());

            // 进行 Kerberos 认证
            lc.login();
            // 获取 Subject
            Subject subject = lc.getSubject();
//            logger.info("subject:{}", subject);
            // 在这里可以使用 subject 来执行进一步的操作,如访问受限资源
            // 登出
            lc.logout();
        } catch (LoginException e) {
            // 处理登录异常
            e.printStackTrace();
        }
    }
}

LdapTest测试类

package com.example.ldaptest2;

import com.example.ldaptest2.entity.LdapUser;
import com.example.ldaptest2.mapper.LdapUserAttributeMapper;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.test.context.junit4.SpringRunner;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;

@SpringBootTest
@RunWith(SpringRunner.class)
public class LdapTest {

    @Autowired
    private LdapTemplate ldapTemplate;

    @Test
    public void listUsers() throws NoSuchAlgorithmException {
        AndFilter filter = new AndFilter();
        filter.and(new EqualsFilter("objectClass", "inetOrgPerson"));

        List<LdapUser> users = ldapTemplate.search("ou=People,dc=hdp", filter.encode(), new LdapUserAttributeMapper());
        for (LdapUser user: users ) {
            System.out.println("user: " + user);
            System.out.println("userPassword:" + user.getUserPassword());
            System.out.println(verifySHA(user.getUserPassword(), "123456"));
        }
    }

    @SuppressWarnings(value = "unchecked")
    public static boolean verifySHA(String ldappw, String inputpw) throws NoSuchAlgorithmException {

        // MessageDigest 提供了消息摘要算法,如 MD5 或 SHA,的功能,这里LDAP使用的是SHA-1
        MessageDigest md = MessageDigest.getInstance("SHA-1");

        // 取出加密字符
        if (ldappw.startsWith("{SSHA}")) {
            ldappw = ldappw.substring(6);
        } else if (ldappw.startsWith("{SHA}")) {
            ldappw = ldappw.substring(5);
        }

        // 解码BASE64
        byte[] ldappwbyte = Base64.decode(ldappw);
        byte[] shacode;
        byte[] salt;

        // 前20位是SHA-1加密段,20位后是最初加密时的随机明文
        if (ldappwbyte.length <= 20) {
            shacode = ldappwbyte;
            salt = new byte[0];
        } else {
            shacode = new byte[20];
            salt = new byte[ldappwbyte.length - 20];
            System.arraycopy(ldappwbyte, 0, shacode, 0, 20);
            System.arraycopy(ldappwbyte, 20, salt, 0, salt.length);
        }

        // 把用户输入的密码添加到摘要计算信息
        md.update(inputpw.getBytes());
        // 把随机明文添加到摘要计算信息
        md.update(salt);

        // 按SSHA把当前用户密码进行计算
        byte[] inputpwbyte = md.digest();

        // 返回校验结果
        return MessageDigest.isEqual(shacode, inputpwbyte);
    }
}

SpringVersionUtils测试类

package com.example.ldaptest2;

import org.junit.Test;
import org.springframework.boot.SpringBootVersion;
import org.springframework.core.SpringVersion;
import org.springframework.security.core.SpringSecurityCoreVersion;

/**
 * 获取Spring、SpringBoot版本号
 * @Author 211145187
 * @Date 2022/11/12 10:42
 **/
public class SpringVersionUtils {

    /**
     * Spring Security:4.2.3.RELEASE
     * Spring Version:4.3.9.RELEASE
     * SpringBoot Version:1.4.7.RELEASE
     */
    @Test
    public void getSpringVersion() {
        System.out.println("Spring Security:" + SpringSecurityCoreVersion.getVersion());
        String versionSpring = SpringVersion.getVersion();
        String versionSpringBoot = SpringBootVersion.getVersion();
        System.out.println("Spring Version:" + versionSpring);
        System.out.println("SpringBoot Version:" + versionSpringBoot);
    }

}

三、可能碰到的报错

错误场景1:javax.security.auth.login.LoginException: Receive timed out

完整错误

Receive timed out
javax.security.auth.login.LoginException: Receive timed out
        at com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:812)
        at com.sun.security.auth.module.Krb5LoginModule.login(Krb5LoginModule.java:618)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at javax.security.auth.login.LoginContext.invoke(LoginContext.java:755)
        at javax.security.auth.login.LoginContext.access$000(LoginContext.java:195)
        at javax.security.auth.login.LoginContext$4.run(LoginContext.java:682)
        at javax.security.auth.login.LoginContext$4.run(LoginContext.java:680)
        at java.security.AccessController.doPrivileged(Native Method)
        at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680)
        at javax.security.auth.login.LoginContext.login(LoginContext.java:587)
        at com.example.ldaptest2.controller.TestController.authenticateUserByPassword(TestController.java:78)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:121)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:100)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
        at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:748)
Caused by: java.net.SocketTimeoutException: Receive timed out
        at java.net.PlainDatagramSocketImpl.receive0(Native Method)
        at java.net.AbstractPlainDatagramSocketImpl.receive(AbstractPlainDatagramSocketImpl.java:143)
        at java.net.DatagramSocket.receive(DatagramSocket.java:812)
        at sun.security.krb5.internal.UDPClient.receive(NetClient.java:206)
        at sun.security.krb5.KdcComm$KdcCommunication.run(KdcComm.java:404)
        at sun.security.krb5.KdcComm$KdcCommunication.run(KdcComm.java:364)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.security.krb5.KdcComm.send(KdcComm.java:348)
        at sun.security.krb5.KdcComm.sendIfPossible(KdcComm.java:253)
        at sun.security.krb5.KdcComm.send(KdcComm.java:229)
        at sun.security.krb5.KdcComm.send(KdcComm.java:200)
        at sun.security.krb5.KrbAsReqBuilder.send(KrbAsReqBuilder.java:343)
        at sun.security.krb5.KrbAsReqBuilder.action(KrbAsReqBuilder.java:447)
        at com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:770)
        ... 100 more

我的代码

@GetMapping(value = "/authenticateUserByPassword")
public void authenticateUserByPassword() {
     try {
         System.setProperty("java.security.krb5.conf", "/temporary/krb5.conf");
         // 创建 LoginContext 对象,并为其提供自定义 Configuration
         LoginContext lc = new LoginContext("KrbLogin", null, new MyCallbackHandler(), new CustomConfigurationByPassword());

         // 进行 Kerberos 认证
         lc.login();
         // 获取 Subject
         Subject subject = lc.getSubject();
//            logger.info("subject:{}", subject);
         // 在这里可以使用 subject 来执行进一步的操作,如访问受限资源
         // 登出
         lc.logout();
     } catch (LoginException e) {
         // 处理登录异常
         e.printStackTrace();
         logger.error("LoginException e:{}", e.getMessage());
     }
 }

查看38.162服务器上/var/log/krb5kdc.log日志,看详细报错:

otp: Loaded
Jun 17 14:51:41 localhost.localdomain krb5kdc[6531](info): setting up network...
krb5kdc: setsockopt(12,IPV6_V6ONLY,1) worked
krb5kdc: setsockopt(14,IPV6_V6ONLY,1) worked
Jun 17 14:51:41 localhost.localdomain krb5kdc[6531](info): set up 4 sockets
Jun 17 14:51:41 localhost.localdomain krb5kdc[6533](info): commencing operation
Jun 17 14:52:01 localhost.localdomain krb5kdc[6533](info): AS_REQ (8 etypes {18 17 20 19 16 23 25 26}) 127.0.0.1: CLIENT_NOT_FOUND: ldap/admin@NODE3.COM for kadmin/127.0.0.1@NODE3.COM, Client not found in Kerberos database
Jun 17 14:57:22 localhost.localdomain krb5kdc[6533](info): AS_REQ (8 etypes {18 17 20 19 16 23 25 26}) 127.0.0.1: CLIENT_NOT_FOUND: ldap/admin@NODE3.COM for kadmin/127.0.0.1@NODE3.COM, Client not found in Kerberos database
Jun 18 01:44:05 localhost.localdomain krb5kdc[6533](info): AS_REQ (4 etypes {18 17 16 23}) 127.0.0.1: CLIENT_NOT_FOUND: ldap/bridge1@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM, Client not found in Kerberos database
Jun 18 01:44:05 localhost.localdomain krb5kdc[6533](info): AS_REQ (4 etypes {18 17 16 23}) 127.0.0.1: CLIENT_NOT_FOUND: ldap/bridge1@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM, Client not found in Kerberos database
Jun 18 07:25:44 localhost.localdomain krb5kdc[6533](info): AS_REQ (8 etypes {18 17 16 23 25 26 20 19}) 127.0.0.1: ISSUE: authtime 1718666744, etypes {rep=18 tkt=18 ses=18}, ldapadmin@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM
Jun 18 07:29:04 localhost.localdomain krb5kdc[6533](info): AS_REQ (4 etypes {18 17 16 23}) 127.0.0.1: ISSUE: authtime 1718666944, etypes {rep=18 tkt=18 ses=18}, ldapadmin@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM
Jun 18 09:21:25 localhost.localdomain krb5kdc[6533](info): AS_REQ (4 etypes {18 17 16 23}) 127.0.0.1: ISSUE: authtime 1718673685, etypes {rep=18 tkt=18 ses=18}, ldapadmin@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM
Jun 18 11:10:13 localhost.localdomain krb5kdc[6533](info): AS_REQ (4 etypes {18 17 16 23}) 127.0.0.1: ISSUE: authtime 1718680213, etypes {rep=18 tkt=18 ses=18}, ldapadmin@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM
Jun 18 11:16:22 localhost.localdomain krb5kdc[6533](info): AS_REQ (4 etypes {18 17 16 23}) 127.0.0.1: ISSUE: authtime 1718680582, etypes {rep=18 tkt=18 ses=18}, ldapadmin@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM
Jun 18 11:17:08 localhost.localdomain krb5kdc[6533](info): AS_REQ (8 etypes {18 17 20 19 16 23 25 26}) 127.0.0.1: ISSUE: authtime 1718680628, etypes {rep=18 tkt=18 ses=18}, ldapadmin@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM
Jun 18 11:17:20 localhost.localdomain krb5kdc[6533](info): AS_REQ (8 etypes {18 17 20 19 16 23 25 26}) 127.0.0.1: ISSUE: authtime 1718680640, etypes {rep=18 tkt=18 ses=18}, ldapadmin@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM
Jun 18 11:17:26 localhost.localdomain krb5kdc[6533](info): AS_REQ (8 etypes {18 17 20 19 16 23 25 26}) 127.0.0.1: ISSUE: authtime 1718680646, etypes {rep=18 tkt=18 ses=18}, ldapadmin@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM
Jun 18 11:18:33 localhost.localdomain krb5kdc[6533](info): AS_REQ (8 etypes {18 17 20 19 16 23 25 26}) 127.0.0.1: ISSUE: authtime 1718680713, etypes {rep=18 tkt=18 ses=18}, ldapadmin@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM
Jun 18 11:18:44 localhost.localdomain krb5kdc[6533](info): AS_REQ (4 etypes {18 17 16 23}) 127.0.0.1: ISSUE: authtime 1718680724, etypes {rep=18 tkt=18 ses=18}, ldapadmin@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM
Jun 19 03:37:41 localhost.localdomain krb5kdc[6533](info): AS_REQ (4 etypes {18 17 16 23}) 127.0.0.1: ISSUE: authtime 1718739461, etypes {rep=18 tkt=18 ses=18}, ldapadmin@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM
Jun 19 03:38:42 localhost.localdomain krb5kdc[6533](info): AS_REQ (8 etypes {18 17 16 23 25 26 20 19}) 127.0.0.1: ISSUE: authtime 1718739522, etypes {rep=18 tkt=18 ses=18}, ldapadmin@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM
Jun 19 03:41:16 localhost.localdomain krb5kdc[6533](info): AS_REQ (8 etypes {18 17 16 23 25 26 20 19}) 127.0.0.1: ISSUE: authtime 1718739676, etypes {rep=18 tkt=18 ses=18}, ldap/bridge1@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM
Jun 19 03:41:22 localhost.localdomain krb5kdc[6533](info): AS_REQ (8 etypes {18 17 16 23 25 26 20 19}) 127.0.0.1: ISSUE: authtime 1718739682, etypes {rep=18 tkt=18 ses=18}, ldapadmin@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM
Jun 19 03:41:59 localhost.localdomain krb5kdc[6533](info): AS_REQ (8 etypes {18 17 16 23 25 26 20 19}) 127.0.0.1: ISSUE: authtime 1718739719, etypes {rep=18 tkt=18 ses=18}, ldapadmin@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM
Jun 19 03:51:21 localhost.localdomain krb5kdc[6533](info): AS_REQ (8 etypes {18 17 20 19 16 23 25 26}) 127.0.0.1: ISSUE: authtime 1718740281, etypes {rep=18 tkt=18 ses=18}, testldap3@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM
Jun 19 03:51:36 localhost.localdomain krb5kdc[6533](info): AS_REQ (8 etypes {18 17 16 23 25 26 20 19}) 127.0.0.1: ISSUE: authtime 1718740296, etypes {rep=18 tkt=18 ses=18}, ldapadmin@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM
Jun 19 03:53:15 localhost.localdomain krb5kdc[6533](info): AS_REQ (4 etypes {18 17 16 23}) 127.0.0.1: ISSUE: authtime 1718740395, etypes {rep=18 tkt=18 ses=18}, ldapadmin@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM
Jun 19 03:53:55 localhost.localdomain krb5kdc[6533](info): AS_REQ (4 etypes {18 17 16 23}) 127.0.0.1: ISSUE: authtime 1718740435, etypes {rep=18 tkt=18 ses=18}, testldap3@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM
Jun 19 03:55:13 localhost.localdomain krb5kdc[6533](info): AS_REQ (4 etypes {18 17 16 23}) 127.0.0.1: ISSUE: authtime 1718740513, etypes {rep=18 tkt=18 ses=18}, testldap3@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM
Jun 19 03:58:19 localhost.localdomain krb5kdc[6533](info): AS_REQ (8 etypes {18 17 20 19 16 23 25 26}) 127.0.0.1: CLIENT_NOT_FOUND: ldaptest3@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM, Client not found in Kerberos database
Jun 19 05:27:53 localhost.localdomain krb5kdc[6533](info): closing down fd 14
Jun 19 05:27:53 localhost.localdomain krb5kdc[6533](info): closing down fd 13
Jun 19 05:27:53 localhost.localdomain krb5kdc[6533](info): closing down fd 12
Jun 19 05:27:53 localhost.localdomain krb5kdc[6533](info): closing down fd 11
Jun 19 05:27:53 localhost.localdomain krb5kdc[6533](info): shutting down

场景描述:我把demo项目打包运行在209服务器,而ldap+kerberos安装在38.162服务器上,进行接口联调。

错误原因

主要看这行:CLIENT_NOT_FOUND: ldaptest3@NODE3.COM for krbtgt/NODE3.COM@NODE3.COM, Client not found in Kerberos database

再看这行:javax.security.auth.login.LoginException: Receive timed out

报错显示javax.security.auth.login.LoginException: Receive timed out,总感觉代码没连接kerberos,或者说感觉java代码客户端对面kerberos不认识。
之前我是demo运行在38.162就能认证应该是能识别,当我把demo放在209服务器上就报错了
猜测可能是209服务器的连接不上38.162的88端口,所以应该是网络的问题

举例说明:

举例说明:56.70服务器运行telnet 命令查看88端口是否可用

[root@localhost temporary]# telnet 10.110.38.162 88
Trying 10.110.38.162...
Connected to 10.110.38.162.
Escape character is '^]'.

209运行telnet 命令查看88端口是否可用

[root@localhost temporary]#  telnet 10.110.38.162 88
Trying 10.110.38.162...
telnet: connect to address 10.110.38.162: Connection timed out
[root@localhost temporary]# 

解决方案:你换台服务器跑项目就能调通了。

错误场景2:javax.security.auth.login.LoginException: Cannot locate KDC

完整错误

Cannot locate KDC
javax.security.auth.login.LoginException: Cannot locate KDC
        at com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:808)
        at com.sun.security.auth.module.Krb5LoginModule.login(Krb5LoginModule.java:618)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at javax.security.auth.login.LoginContext.invoke(LoginContext.java:755)
        at javax.security.auth.login.LoginContext.access$000(LoginContext.java:195)
        at javax.security.auth.login.LoginContext$4.run(LoginContext.java:682)
        at javax.security.auth.login.LoginContext$4.run(LoginContext.java:680)
        at java.security.AccessController.doPrivileged(Native Method)
        at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680)
        at javax.security.auth.login.LoginContext.login(LoginContext.java:587)
        at com.example.ldaptest2.controller.TestController.authenticateUserByPassword(TestController.java:77)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:121)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:100)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
        at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:748)
Caused by: KrbException: Cannot locate KDC
        at sun.security.krb5.Config.getKDCList(Config.java:1189)
        at sun.security.krb5.KdcComm.send(KdcComm.java:218)
        at sun.security.krb5.KdcComm.send(KdcComm.java:200)
        at sun.security.krb5.KrbAsReqBuilder.send(KrbAsReqBuilder.java:343)
        at sun.security.krb5.KrbAsReqBuilder.action(KrbAsReqBuilder.java:447)
        at com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:770)
        ... 100 more
Caused by: KrbException: Generic error (description in e-text) (60) - Unable to locate KDC for realm NODE3.COM
        at sun.security.krb5.Config.getKDCFromDNS(Config.java:1286)
        at sun.security.krb5.Config.getKDCList(Config.java:1162)

错误代码

//用户+密码认证
    @Test
    public void authenticateUserByPassword() {
        try {
            // 创建 LoginContext 对象,并为其提供自定义 Configuration
            LoginContext lc = new LoginContext("KrbLogin", null, new MyCallbackHandler(), new CustomConfigurationByPassword());

            // 进行 Kerberos 认证
            lc.login();
            // 获取 Subject
            Subject subject = lc.getSubject();
//            logger.info("subject:{}", subject);
            // 在这里可以使用 subject 来执行进一步的操作,如访问受限资源
            // 登出
            lc.logout();
        } catch (LoginException e) {
            // 处理登录异常
            e.printStackTrace();
        }
    }

场景描述:windows本地跑项目,我的ldap+kerberos安装在38.162环境,我想本地windows上连接38.162服务器进行kerberos用户认证。

错误原因:没有注入配置文件,人家代码凭啥能精准找到38.162服务器上,你得导入配置文件啊,因为你的项目中只有ldap服务的一些配置,压根kerberos的相关配置,且代码中只引入CustomConfigurationByPassword,里面压根没有指定IP啥的地方。

解决方案:设置:System.setProperty(“java.security.krb5.conf”, “/xxx/krb5.conf”);

正确代码:

//用户+密码认证
    @Test
    public void authenticateUserByPassword() {
        try {
            System.setProperty("java.security.krb5.conf", "C:\\Users\\211145187\\Desktop\\fsdownload\\krb5.conf");
            // 创建 LoginContext 对象,并为其提供自定义 Configuration
            LoginContext lc = new LoginContext("KrbLogin", null, new MyCallbackHandler(), new CustomConfigurationByPassword());

            // 进行 Kerberos 认证
            lc.login();
            // 获取 Subject
            Subject subject = lc.getSubject();
//            logger.info("subject:{}", subject);
            // 在这里可以使用 subject 来执行进一步的操作,如访问受限资源
            // 登出
            lc.logout();
        } catch (LoginException e) {
            // 处理登录异常
            e.printStackTrace();
        }
    }

思路讲解:首先把配置文件krb5.conf下载下来,然后当你代码注入System.setProperty配置文件的时候,项目就会读取配置文件内容,其中的kdc就配置了10.110.38.162,所以项目代码就知道连接到哪里进行kerberos认证了。

krb5.conf

# Configuration snippets may be placed in this directory as well
includedir /etc/krb5.conf.d/

[logging]
 default = FILE:/var/log/krb5libs.log
 kdc = FILE:/var/log/krb5kdc.log
 admin_server = FILE:/var/log/kadmind.log

[libdefaults]
 dns_lookup_realm = false
 ticket_lifetime = 24h
 #renew_lifetime = 7d
 forwardable = true
 rdns = false
 pkinit_anchors = FILE:/etc/pki/tls/certs/ca-bundle.crt
 default_realm = NODE3.COM
# default_ccache_name = KEYRING:persistent:%{uid}

[realms]
 NODE3.COM = {
 # kdc = kdc.node.com
 # admin_server = kdc.node.com
  kdc = 10.110.38.162
  admin_server = 10.110.38.162
  ldap_servers = ldap://10.110.38.162:389

 # kdc = node3.com:88
 # admin_server = node3.com:749
 # default_domain = NODE3.COM
 }

[domain_realm]
 .node3.com = NODE3.COM
 node3.com = NODE3.COM

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1842979.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入了解 AndroidX ConstraintLayout 中的 Barrier

androidx.constraintlayout.widget.Barrier&#xff08;简称Barrier&#xff09;是 ConstraintLayout 2.0 中引入的一个新特性&#xff0c;它可以极大地简化复杂布局的实现。本文将详细介绍Barrier 的概念、使用方法以及在实际开发中的应用场景。 什么是 Barrier&#xff1f; …

Linux-账号和权限管理

目录 一、管理用户账号 1、用户账号类型 2、UID--身份标识 3、UID的分类 ​4、用户账号文件​ 5、chage-修改账号密码 5.1、chage—使用格式&#xff1a; 5.2、chage—使用参数&#xff1a; ​6、添加用户账号与管理 6.1、useradd—添加用户 6.2、passwd—设置/修改…

五大数据防泄漏系统排名|高效实用的防泄漏软件有哪些

在数字化时代&#xff0c;数据泄露已成为企业面临的重要安全挑战之一。为了有效应对这一挑战&#xff0c;企业需要借助先进的数据泄露防护系统来保护其敏感信息免受非法访问、使用和泄露。以下是五大备受推崇的数据泄露防护系统&#xff0c;它们各具特色&#xff0c;功能强大&a…

深度学习(十四)——优化器

前言 反向传播可以求出神经网路中每个需要调节参数的梯度(grad)&#xff0c;优化器可以根据梯度进行调整&#xff0c;达到降低整体误差的作用。下面我们对优化器进行介绍。 1. 如何使用优化器 官方文档:torch.optim — PyTorch 2.0 documentation &#xff08;1&#xff09;构…

DataOps真能“降本增效”?

在各行各业中&#xff0c;越来越多的公司开始重视收集数据&#xff0c;并寻找创新方法来获得真实可行的商业成果&#xff0c;并且愿意投入大量时间和金钱来实现这一目标。 据IDC称&#xff0c;数据和分析软件及云服务市场规模在 2021 年达到了 900 亿美元&#xff0c;随着企业继…

T230L单路HDMI高清采集卡带1路HDMI环出

同三维T230L单路HDMI高清采集卡 带1路HDMI环出 产品简介&#xff1a; 同三维T230L是在老款T230L基础上升级的产品&#xff0c;由输入环出4K30升级到4K60,此款产品是一款单路&#xff08;1路&#xff09;HDMI高清音视频采集卡&#xff0c;还带1路HDMI环出&#xff0c;可采集1路…

自由度与反证法

在 一道全等三角形几何证明题 的最后我使用反证法获得了解法三&#xff0c;但只是稍微提到了自由度&#xff0c;本文详细说一下&#xff0c;然后下一篇文章给出我的一个求最小生成树的新方法&#xff0c;同样基于自由度和反证法。 再次给出那道几何题&#xff0c;并给出一些话…

手机携号转网接口查询与对接指南:技术开发者必备手册

在当今通信技术飞速发展的背景下&#xff0c;手机携号转网已成为推动电信市场竞争、保障用户权益的重要手段。而对于技术开发者而言&#xff0c;掌握手机携号转网接口的查询与对接方法&#xff0c;无疑是提升服务兼容性和用户满意度的关键。 比如如下应用场景&#xff1a; 1.…

如何删除电脑自带的游戏

要删除电脑自带的游戏&#xff0c;如扫雷和纸牌&#xff0c;你可以按照以下步骤操作&#xff0c;这些步骤基于Windows操作系统&#xff1a; 对于Windows 7及其更早版本 打开控制面板选择“程序”打开或关闭Windows功能找到并取消勾选游戏 对于Windows 10及更高版本 打开“设…

基于Springboot+vue 共享车位系统小程序-计算机毕设 附源码94559

Springboot 共享车位系统小程序 摘 要 在信息飞速发展的今天&#xff0c;网络已成为人们重要的信息交流平台。每天都有大量的农产品需要通过网络发布&#xff0c;为此&#xff0c;本人开发了一个基于springboot共享车位系统小程序。 对于本共享车位系统的设计来说&#xff0c;…

Ike-scan一键发现通过互联网的IPsec VPN服务器(KALI工具系列二十八)

目录 1、KALI LINUX 简介 2、Ike-scan工具简介 3、信息收集 3.1 目标主机IP&#xff08;服务器&#xff09; 3.2 KALI的IP 4、操作示例 4.1 简单扫描 4.2 范围扫描 4.3 扫描多个目标 4.4 输出扫描结果 4.5 特殊扫描 5、总结 1、KALI LINUX 简介 Kali Linux 是一个功…

【R语言】对一个Plot绘制多个图,并且每个图单元也包含多个图

以一个Plot绘制五行六列共30个图&#xff0c;然后每30个图单元包含两个图为例&#xff1a; 如下图所示&#xff1a; 代码如下&#xff1a; for (i in 1:(5*6)) {create_subplots <- function() {library(ggplot2)library(dplyr)library(tidyr)# 创建一个随机的数据框simula…

传统后端SQL数据层替代解决方案: 内置数据源+JdbcTemplate+H2数据库 详解

内置数据源 我们回顾一下druid数据源的配置方式 通过type属性指定数据源的类型 导入依赖 starter就使用了spring的自动装配功能 格式二是在引入druid的依赖的基础上 进行的一种配置方式 Tomcat内部也可以进行数据源的配置 轻量级中最快的数据源对象 我们切换德鲁伊连接池 我…

springboot vue 开源 会员收银系统 (7) 收银台的完善 新增开卡 结算

前言 完整版演示 开发版演示 在前面的开发中&#xff0c;我们成功完成了商品分类和商品信息的搭建&#xff0c;开发了收银台基础。现在&#xff0c;我们将进一步完善收银台的功能&#xff0c;添加开卡和结算功能&#xff0c;并在后台实现会员卡的创建和订单保存。同时&#xff…

船舶行业信息安全解决方案介绍

船舶行业信息安全背景&#xff1a; 近年来随着经济复苏、疫情与国际形势影响国内外船舶海运业务蓬勃发展&#xff0c;在业务量激增的背景下出现多类信息安全事件。其中2017年&#xff0c;马士基集团遭到勒索软件攻击&#xff0c;内部业务系统和码头操作系统均受到严重影响&…

U盘数据恢复,小白也适用的4个方法!

你是否曾经遇到过这样的情况&#xff1a;当你满怀期待地插入U盘&#xff0c;准备欣赏那些珍贵的照片、视频或重要文件时&#xff0c;却发现U盘中的数据仿佛被一阵海风轻轻吹散&#xff0c;只剩下空荡荡的文件夹和一片茫然。那种失落感&#xff0c;就像是突然发现手中的藏宝图被…

(四十三)Vue Router之嵌套路由

文章目录 什么是嵌套路由嵌套路由的使用demo 上一篇&#xff1a;&#xff08;四十二&#xff09;Vue之路由及其基本使用Vue Router 什么是嵌套路由 实际生活中的应用界面&#xff0c;有可能由多层嵌套的组件组合而成。同样地&#xff0c;URL 中各段动态路径也按某种结构对应嵌…

数据可视化案例

数据可视化案例 相关的技术&#xff1a;scrapy、pandas、pyecharts。 使用豆瓣电影中的数据来进行可视化&#xff0c;网址&#xff1a;豆瓣电影 Top 250 (douban.com) 一、网页数据分析 我们需要爬取的是豆瓣电影Top250网页每一页的电影名称、图片链接、导演、年份、国家、电…

Bert模型实现中文新闻文本分类

Bert基于Transformer架构是解决自然语言处理的深度学习模型&#xff0c;常使用在文本分类、情感分析、词性标注等场合。 本文将使用Bert模型对中文文本进行分类&#xff0c;其中训练集数据18W条&#xff0c;验证集数据1W条,包含10个类别的文本数据&#xff0c;数据可以自己从Ka…

大润发超市购物卡怎么用?

收到大润发超市的礼品卡以后&#xff0c;我才发现&#xff0c;最近的大润发也得十来公里 为了100块的大润发打车也太不划算了 叫外送也不在配送范围内 最后没办法&#xff0c;在收卡云上出掉了&#xff0c;还好最近价格不错&#xff0c;也不亏&#xff0c;收卡云的到账速度也…