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

在这里插入图片描述

文章目录

  • 一、背景
  • 二、代码
    • 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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringCloudAlibaba组件之间的版本兼容问题

我之前的SpringCloud项目以及使用的组件的版本是这些 但是我不知道具体的版本兼容问题&#xff0c;以及各种组件之间对应的版本 想要使用我们的springcloud和springcloudAlibaba组件&#xff0c;我们就要版本对应&#xff0c;不然就是一堆依赖报错&#xff0c;要不就是缺了这个…

业余时间做跨境电商实现经济自由,我是怎么做的?

在知乎问答上翻阅大家非常感兴趣的问题&#xff0c;解答一些疑惑的同时&#xff0c;发现大家对跨境电商还是很感兴趣的&#xff0c;类似“小白如何入局跨境电商&#xff1f;2024跨境电商平台&#xff0c;哪些值得做&#xff1f;现在电商哪个平台好做?”等的这些主观问题&#…

Java程序员Python一小时速成

背景 由于最近要开发一些AI LLM&#xff08;Large Language Model 大语言模型&#xff09;应用程序&#xff0c;然后又想使用LangChain&#xff08;LangChain 是一个用于构建和操作大语言模型&#xff08;LLMs&#xff09;的框架&#xff0c;旨在帮助开发者更方便地集成和使用…

Vant2组件库的基础应用

目录 一、Picker 选择器 1.1、数组对象处理 1.2、每个选项颜色设置 二、滚动分页加载列表 三、Calendar 日历(可选范围限制) 四、input值过滤 官网&#xff1a;Vant 2 - Mobile UI Components built on Vue 一、Picker 选择器 官网示例数据&#xff1a; columns: [杭州…

Anti-human IL-12/-23 (p40) mAb (MT3279H), azide free

Anti-human IL-12/-23 (p40) mAb (MT3279H), azide free该单克隆抗体用于中和人IL-12/-23的生物活性。 产品详情&#xff1a; 免疫原&#xff1a;人重组IL-23蛋白 Isotype: mouse IgG2b Specificity: 天然和重组人IL-12和 IL-23蛋白的p40 subunit 浓度&#xff1a;1mg/ml …

查看nginx安装/配置路径,一个服务器启动两个nginx

查看nginx安装/配置路径 查看nginx的pid&#xff1a; ps -ef | grep nginx查看pid对应服务的启动路径 ll /proc/2320/exe使用检查配置文件命令&#xff0c;查看配置文件位置 /usr/local/nginx/sbin/nginx -t一个服务启动两个nginx 拷贝一份程序&#xff0c;cpbin是我自己创…

【HarmonyOS NEXT】har 包的构建生成过程

Har模块文件结构 构建HAR 打包规则 开源HAR除了默认不需要打包的文件&#xff08;build、node_modules、oh_modules、.cxx、.previewer、.hvigor、.gitignore、.ohpmignore&#xff09;和.gitignore/.ohpmignore中配置的文件&#xff0c;cpp工程的CMakeLists.txt&#xff0c;…

[CR]厚云填补_基于相似像素的渐进式缺口填补方法PGFCTS

Progressive gap-filling in optical remote sensing imagery through a cascade of temporal and spatial reconstruction models--Remote Sensing of Environment--2024.06.01 Abstract 在光学遥感图像的预处理中&#xff0c;由于云层较厚或传感器发生故障而产生的空白填充一…

群晖NAS本地部署并运行一个基于大语言模型Llama2的个人本地聊天机器人

前言 本文主要分享如何在群晖 NAS 本地部署并运行一个基于大语言模型 Llama 2 的个人本地聊天机器人并结合内网穿透工具发布到公网远程访问。本地部署对设备配置要求高一些,如果想要拥有比较好的体验,可以使用高配置的服务器设备. 目前大部分大语言模型的产品都是基于网络线上…

律所优选管理软件排名:Alpha法律智能操作系统领先行业

面对庞大复杂的管理体量&#xff0c;律所一体化建设面临的首要问题便是信息化系统的建设与应用&#xff0c;即统一管理平台的问题。Alpha法律智能操作系统集法律大数据、律所管理、人工智能于一体&#xff0c;从业务、人员、信息三个板块最大限度支持律所数字化建设&#xff0c…

电脑桌面文件夹删除不了怎么办?6种方法快速解决,建议收藏!

桌面文件夹删不掉怎么办&#xff1f;有时会遇到桌面上的文件夹无法删除的问题&#xff0c;这是由于文件夹被系统进程或某些应用占用&#xff0c;或者是由于权限设置等原因造成的。以下是解决桌面文件夹无法删除问题的方法&#xff0c;帮助你有效地清理桌面环境。 桌面文件夹删不…

南京邮电大学计算机网络实验二(网络路由器配置RIP协议)

文章目录 一、 实验目的和要求二、 实验环境(实验设备)三、 实验步骤四、实验小结&#xff08;包括问题和解决方法、心得体会、意见与建议等&#xff09;五、报告资源 一、 实验目的和要求 掌握思科路由器的运行过程&#xff0c;掌握思科路由器的硬件连线与接口&#xff0c;掌…

HNU-计算机系统(CSAPP)实验一 原型机vspm1.0

一、题目 【实验目的】 &#xff08;1&#xff09;了解冯诺伊曼体系结构&#xff1b; &#xff08;2&#xff09;理解指令集结构及其作用&#xff1b; &#xff08;3&#xff09;理解计算机的运行过程&#xff0c;就是指令的执行过程&#xff0c;并初步掌握调试方法。 【实…

黑马苍穹外卖4 店铺营业状态设置+Redis基础

店铺营业状态设置 Redis MySQL Java并发 JavaMVC 计算机网络 操作系统 算法&#xff0c;后端面试主要是这些&#xff0c;外加项目 Redis 数据库&#xff0c;基于内存存储的key-value结构。 mysql是磁盘存储&#xff0c;通过二维表存储。 在文件夹目录打开cmd 服务端&#xf…

HNU操作系统2023期中考试试卷及参考答案

本试题参考 甘晴void 的CSDN博客【2.2】操作系统OS_甘晴void的博客-CSDN博客&#xff0c;本意为期中复习自用&#xff0c;答案在其基础上进行进一步完善&#xff0c;若有错误还请指正&#xff01; 第一题&#xff1a;基础题&#xff08;20分&#xff09; 1.1&#xff08;4分&a…

Windows反截屏开发实现

文章目录 Windows反截屏开发实现1. SetWindowDisplayAffinity2. 反截屏系统3. 总结 Windows反截屏开发实现 最近在我们云桌面中需要做到反截屏能力&#xff0c;所谓反截屏就是我们无法通过截图软件&#xff08;微信&#xff0c;QQ&#xff0c;截图等程序&#xff09;截取桌面的…

lock-锁的概念

锁的简介 锁是计算机协调多个进程或线程并发访问某一资源的机制&#xff08;避免发生资源争抢&#xff09; 在并发环境下&#xff0c;多个线程会对同一个资源进行争抢&#xff0c;可能会导致数据不一致的问题。为了解决这一问题&#xff0c;需要通过一种抽象的锁来对资源进行…

springboot + Vue前后端项目(第十八记)

项目实战第十八记 写在前面1. 前台页面搭建&#xff08;Front.vue&#xff09;2. 路由3.改动登录页面Login.vue4. 前台主页面搭建Home.vue总结写在最后 写在前面 本篇主要讲解系统前台搭建&#xff0c;通常较大的项目都会搭建前台 1. 普通用户登录成功后前台页面效果&#xf…

RestTemple请求GET接口403

问题描述 使用oss接口获取资源的时候&#xff0c;通过浏览器可以直接下载&#xff0c;在代码中使用RestTemplate的get方式访问的时候&#xff0c;出现403错误 问题排查 因为返回状态码是403&#xff0c;就想着是不是授权问题&#xff0c;因为有的接口是有防抓取规则的&…

Java实现自动定时任务配置并判断当天是否需要执行示例

最近接到一个需求&#xff0c;用户要能配置一个定时循环的任务&#xff0c;就是和手机闹钟循环差不多&#xff0c;设置好比如周一、周二、周三&#xff0c;那么在这几天内这个任务就需要自动执行 需求不复杂&#xff0c;首先我需要判断当前是周几&#xff0c;当然用户说了让我…