当前位置: 首页 > 知识库问答 >
问题:

使用带Spring Security的active directory LDAP进行身份验证时凭据错误

巩光誉
2023-03-14

我试图使用Spring Security在我的REST控制器前执行身份验证和授权,该控制器也通过SSL进行保护。我的代码主要来自https://spring.io/guides/gs/authenticating-ldap/的示例

如链接所示,应用程序使用嵌入式LDAP服务器正常工作。我连接到我的主页https://localhost:9000/training/trackerHome并使用用户“ben”和密码“benspassword”(如链接中所指定)登录。一切都很好。

但是当我更新我的属性并尝试连接到真正的LDAP服务器时,我只是不断收到登录页面上写着“不良凭据”的错误。错误日志如下:

training-server_1    | 2020-11-10 17:07:23.728 DEBUG 1 --- [nio-8443-exec-2] o.s.security.web.FilterChainProxy        : /login at position 1 of 14 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
training-server_1    | 2020-11-10 17:07:23.728 DEBUG 1 --- [nio-8443-exec-2] o.s.security.web.FilterChainProxy        : /login at position 2 of 14 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
training-server_1    | 2020-11-10 17:07:23.729 DEBUG 1 --- [nio-8443-exec-2] w.c.HttpSessionSecurityContextRepository : HttpSession returned null object for SPRING_SECURITY_CONTEXT
training-server_1    | 2020-11-10 17:07:23.729 DEBUG 1 --- [nio-8443-exec-2] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@1b6d157. A new one will be created.
training-server_1    | 2020-11-10 17:07:23.730 DEBUG 1 --- [nio-8443-exec-2] o.s.security.web.FilterChainProxy        : /login at position 3 of 14 in additional filter chain; firing Filter: 'HeaderWriterFilter'
training-server_1    | 2020-11-10 17:07:23.730 DEBUG 1 --- [nio-8443-exec-2] o.s.security.web.FilterChainProxy        : /login at position 4 of 14 in additional filter chain; firing Filter: 'CsrfFilter'
training-server_1    | 2020-11-10 17:07:23.740 DEBUG 1 --- [nio-8443-exec-2] o.s.security.web.FilterChainProxy        : /login at position 5 of 14 in additional filter chain; firing Filter: 'LogoutFilter'
training-server_1    | 2020-11-10 17:07:23.740 DEBUG 1 --- [nio-8443-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/logout'
training-server_1    | 2020-11-10 17:07:23.741 DEBUG 1 --- [nio-8443-exec-2] o.s.security.web.FilterChainProxy        : /login at position 6 of 14 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
training-server_1    | 2020-11-10 17:07:23.741 DEBUG 1 --- [nio-8443-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login'; against '/login'
training-server_1    | 2020-11-10 17:07:23.742 DEBUG 1 --- [nio-8443-exec-2] w.a.UsernamePasswordAuthenticationFilter : Request is to process authentication
training-server_1    | 2020-11-10 17:07:23.743 DEBUG 1 --- [nio-8443-exec-2] o.s.s.authentication.ProviderManager     : Authentication attempt using org.springframework.security.ldap.authentication.LdapAuthenticationProvider
training-server_1    | 2020-11-10 17:07:23.744 DEBUG 1 --- [nio-8443-exec-2] o.s.s.l.a.LdapAuthenticationProvider     : **Processing authentication request for user: john.doe**
training-server_1    | 2020-11-10 17:07:23.784 DEBUG 1 --- [nio-8443-exec-2] w.a.UsernamePasswordAuthenticationFilter : Authentication request failed: org.springframework.security.authentication.**BadCredentialsException: Bad credentials**
training-server_1    |
training-server_1    | org.springframework.security.authentication.BadCredentialsException: Bad credentials
training-server_1    |  at org.springframework.security.ldap.authentication.LdapAuthenticationProvider.doAuthentication(LdapAuthenticationProvider.java:197) ~[spring-security-ldap-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.ldap.authentication.AbstractLdapAuthenticationProvider.authenticate(AbstractLdapAuthenticationProvider.java:85) ~[spring-security-ldap-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174) ~[spring-security-core-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:199) ~[spring-security-core-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94) ~[spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) ~[spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:124) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) [spring-security-web-5.1.1.RELEASE.jar!/:5.1.1.RELEASE]
training-server_1    |  at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.2.RELEASE.jar!/:5.1.2.RELEASE]
training-server_1    |  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:770) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_212]
training-server_1    |  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_212]
training-server_1    |  at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.12.jar!/:9.0.12]
training-server_1    |  at java.lang.Thread.run(Thread.java:748) [na:1.8.0_212]
training-server_1    |
training-server_1    | 2020-11-10 17:07:23.785 DEBUG 1 --- [nio-8443-exec-2] w.a.UsernamePasswordAuthenticationFilter : Updated SecurityContextHolder to contain null Authentication
training-server_1    | 2020-11-10 17:07:23.786 DEBUG 1 --- [nio-8443-exec-2] w.a.UsernamePasswordAuthenticationFilter : Delegating to authentication failure handler org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler@63d9b403
training-server_1    | 2020-11-10 17:07:23.786 DEBUG 1 --- [nio-8443-exec-2] .a.SimpleUrlAuthenticationFailureHandler : Redirecting to /login?error
training-server_1    | 2020-11-10 17:07:23.786 DEBUG 1 --- [nio-8443-exec-2] o.s.s.web.DefaultRedirectStrategy        : Redirecting to '/login?error'
training-server_1    | 2020-11-10 17:07:23.787 DEBUG 1 --- [nio-8443-exec-2] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
training-server_1    | 2020-11-10 17:07:23.787 DEBUG 1 --- [nio-8443-exec-2] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed

我困惑的一部分是密码的处理。我不确定要为密码编码器指定什么(如果有的话)?我担心我可能正在编码一个已经编码的密码。我尝试了所有可能的密码编码器类型,也没有使用任何密码编码器。仍然会收到错误的凭据错误。

应用使用嵌入式LDAP服务器时的属性:

ldap.server.url=ldap://localhost:8389/dc=springframework,dc=org
spring.ldap.username=
spring.ldap.password=
ldap.password.encoder=bcrypt
ldap.user.dn.pattern="uid={0},ou=people"
ldap.group.search.base="ou=groups"


# Configuration of Spring's embedded LDAP server (used for development and testing)
spring.ldap.embedded.ldif=classpath:test-server.ldif
spring.ldap.embedded.port=8389
spring.ldap.embedded.base-dn=dc=springframework,dc=org

测试服务器。显示用户“ben”定义的ldif摘录

dn: uid=ben,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Ben Alex
sn: Alex
uid: ben
userPassword: $2a$10$c6bSeWPhg06xB1lvmaWNNe4NROmZiSpYhlocU/98HNr2MhIOiSt36

应用使用实际LDAP服务器时的属性:

ldap.server.url=ldap://125.126.127.128:389/DC=MY-LAB,DC=MY-COMPANY,dc=local
spring.ldap.username=MY-Lab\manager.doe
spring.ldap.password=validpassword
ldap.password.encoder=none
ldap.user.dn.pattern="uid={0},ou=MY-LAB"
ldap.group.search.base="ou=MY-LAB"

实际的LDAP服务器结构:

DC=MY-LAB,DC=MY-COMPANY,DC=local[125.126.127.128]
    OU=Domain Controllers
    OU=MY-LAB
        OU=Users
            OU=Outside Users
                CN=Manager Doe
                      (User principal name = manager.doe)
                CN=John Doe
                      (User principal name = john.doe)
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  private static final Logger log = LoggerFactory.getLogger(WebSecurityConfig.class);

  @Value("${ldap.server.url}")
  private String ldapServerUrl;

  @Value("${spring.ldap.username}")
  private String ldapManagerDn;

  @Value("${spring.ldap.password}")
  private String ldapManagerPassword;

  @Value("${ldap.password.encoder}")
  private String ldapPasswordEncoder;

  @Value("${ldap.user.dn.pattern}")
  private String ldapUserDnPattern;

  @Value("${ldap.group.search.base}")
  private String ldapGroupSearchBase;

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().anyRequest().fullyAuthenticated().and().formLogin();
  }


  @Override
  @SuppressWarnings("deprecation")
  public void configure(AuthenticationManagerBuilder auth) throws Exception {

    PasswordEncoder passwordEncoder;
    switch(ldapPasswordEncoder) {
      case "none":
        passwordEncoder = null;
        break;
      case "bcrypt":
        passwordEncoder = new BCryptPasswordEncoder();
        break;
      case "ldap":
        passwordEncoder = new LdapShaPasswordEncoder();
        break;
      case "MD4":
        passwordEncoder = new Md4PasswordEncoder();
        break;
      case "MD5":
        passwordEncoder = new MessageDigestPasswordEncoder("MD5");
        break;
      case "pbkdf2":
        passwordEncoder = new Pbkdf2PasswordEncoder();
        break;
      case "scrypt":
        passwordEncoder = new SCryptPasswordEncoder();
        break;
      case "SHA-1":
        passwordEncoder = new MessageDigestPasswordEncoder("SHA-1");
        break;
      case "SHA-256":
        passwordEncoder = new MessageDigestPasswordEncoder("SHA-256");
        break;
      case "sha256":
        passwordEncoder = new StandardPasswordEncoder();
        break;
      default:
        log.warn("password encoder property not specified. Using default value.");
        passwordEncoder = new BCryptPasswordEncoder();
    }

    if(passwordEncoder != null) {
      auth.ldapAuthentication().userDnPatterns(ldapUserDnPattern).groupSearchBase(ldapGroupSearchBase).contextSource().url(
          ldapServerUrl).managerDn(ldapManagerDn).managerPassword(ldapManagerPassword).and().passwordCompare().passwordEncoder(
              passwordEncoder).passwordAttribute("userPassword");
    } else {
      
auth.ldapAuthentication().userDnPatterns(ldapUserDnPattern).groupSearchBase(ldapGroupSearchBase).contextSource().url(
          ldapServerUrl).managerDn(ldapManagerDn).managerPassword(ldapManagerPassword).and().passwordCompare().passwordAttribute(
              "userPassword");
    }
  }
}

你知道我做错了什么吗?让真实LDAP服务器的身份验证总是返回“坏凭证”?

共有1个答案

丁宏浚
2023-03-14

实际LDAP中的密码编码器是什么?你确定那是ldap。暗语编码器等于它。例如,如果是sha1,则为ldap的值。暗语编码器应为SHA-1。如果你不想对密码进行编码。请按如下方式修复它。希望它对你有用。

import org.springframework.security.crypto.password.NoOpPasswordEncoder;

    switch(ldapPasswordEncoder) {
      case "none":
        passwordEncoder = NoOpPasswordEncoder.getInstance();
        break;
     ....
   }

 类似资料:
  • 我对社交网络分析和twitter api是新手。我想收集关于特定主题的tweets。所以我写了下面的代码 在我的程序中,我需要在哪里提供凭据 谢谢

  • 我试图在一个反应式Spring Boot应用程序中配置一个Spring Security性,该应用程序具有一个Vuejs前端,在未经身份验证时将用户重定向到外部OpenID提供程序(用于身份验证)。在用户通过OpenID提供程序进行身份验证并重定向回应用程序(前端)后,将根据OpenID提供程序的响应创建用户名密码身份验证令牌(身份验证),并手动进行身份验证。 但是,在执行此操作时,应用程序似乎无

  • 问题内容: 我正在编写一个PHP应用程序,该应用程序应允许用户将某些事件添加到私有Google日历中。日历是我所有的,我需要一种使PHP使用固定凭据与日历API通信的方法(每个人都可以使用网站上的表单添加事件,但是日历本身并不公开)。 据我所读,使用v1 API中的ClientLogin可以实现。但是,在v3 API中,可用选项为OAuth2.0或API密钥。使用API​​密钥似乎无效,因为它只能

  • 我正在尝试使用urllib3连接到网页。代码如下所示。 如果我们假设url是需要使用用户名和密码进行身份验证的某个网页,那么我是否使用正确的代码进行身份验证? 我使用urllib2做这件事很舒服,但使用urllib3做不到同样的事情。 非常感谢

  • jwt不应该仅仅用于认证用户吗?我读到过可以在里面存储非敏感的东西,比如用户ID。将权限级别之类的东西存储在令牌中可以吗?这样我可以避免数据库调用。

  • 问题内容: 实用程序类中有一个静态方法,该方法将从URL下载文件。已经设置了身份验证器,以便如果需要用户名和密码,则可以检索凭据。问题是,只要凭据有效,来自第一个成功连接的凭据将用于每个连接后缀。这是一个问题,因为我们的代码是多用户的,并且由于没有为每个连接检查凭据,所以没有适当凭据的用户可能会下载文件。 这是我们正在使用的代码 第一次下载文件时,我只从getPasswordAuthenticat