Spring Security:AnonymousAuthenticationToken vs UsernamePasswordAuthenticationToken

时间:2015-10-29 09:46:32

标签: java spring spring-security soapui

我正在开发Gradle / Java 1.8 / Spring Boot,Spring Integration,Spring Batch,Spring Data Rest项目(我继承了这个项目)。

以下是来自:build.gradle

的依赖项
// Spring Boot
compile("org.springframework.boot:spring-boot-starter-ws")
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-integration")
compile("org.springframework.boot:spring-boot-starter-actuator")
compile("org.springframework.boot:spring-boot-starter-security")
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("org.springframework.boot:spring-boot-starter-batch")

// Spring integration
compile("org.springframework.integration:spring-integration-core")
compile("org.springframework.integration:spring-integration-ws")
compile("org.springframework.integration:spring-integration-jpa")
compile("org.springframework.integration:spring-integration-sftp")

// Spring batch
compile("org.springframework.batch:spring-batch-core")
compile("org.springframework.batch:spring-batch-integration")

// Spring Data REST
compile("org.springframework.data:spring-data-rest-webmvc")

查看应用程序的DEBUG日志,我看到两个主题:

i. [http-nio-8080-exec-1],
ii [[http-nio-8080-exec-2]

第一个调用AnonymousAuthenticationToken并且在@ 15:02:56.731中失败:

org.springframework.security.authentication.AnonymousAuthenticationToken

几毫秒后@ 15:02:56.747第二个成功:     org.springframework.security.authentication.UsernamePasswordAuthenticationToken

E.g。

15:02:56.731 [http-nio-8080-exec-1] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
15:02:56.747 [http-nio-8080-exec-2] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@fb774aa3: Principal: org.springframework.security.core.userdetails.User@36ebcb: Username: user; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN,ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ADMIN, ROLE_USER

15:02:56.731 [http-nio-8080-exec-1] DEBUG o.s.s.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@9324be9, returned: -1
15:02:56.747 [http-nio-8080-exec-2] DEBUG o.s.s.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@9324be9, returned: 1

15:02:56.731 [http-nio-8080-exec-1] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.integration.internalMessagingAnnotationPostProcessor'
15:02:56.747 [http-nio-8080-exec-2] DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Authorization successful

失败的方法:AnonymousAuthenticationToken正在生成异常。

来自application.yml的片段:

# Authentication for "user" to the HTTP endpoints
security:
  user:
    password: blahblahblah
  1. Spring Book是否首先尝试AnonymousAuthenticationToken代码,因为 '用户' application.yml中的字段是空白的吗?

  2. 当我更改了用户'字段到实际值,我的gradle构建在sftp验证中出错:

  3.   

    11:57:25.869 [DEBUG] [TestEventLogger]引起:       11:57:25.869 [DEBUG]这里不允许[TestEventLogger]映射值       11:57:25.869 [DEBUG] [TestEventLogger]在'读者',第33行,第13栏:       11:57:25.880 [DEBUG] [TestEventLogger]密码:blahblahblah       11:57:24.166 [DEBUG] [TestEventLogger] at org.yaml.snakeyaml.scanner.ScannerImpl.fetchValue(ScannerImpl.java:871)       11:57:24.167 [DEBUG] [TestEventLogger] at org.yaml.snakeyaml.scanner.ScannerImpl.fetchMoreTokens(ScannerImpl.java:360)       11:57:24.167 [DEBUG] [TestEventLogger] at org.yaml.snakeyaml.scanner.ScannerImpl.checkToken(ScannerImpl.java:226)       11:57:24.167 [DEBUG] [TestEventLogger] at org.yaml.snakeyaml.parser.ParserImpl $ ParseBlockMappingKey.produce(ParserImpl.java:558)       11:57:24.168 [DEBUG] [TestEventLogger]在org.yaml.snakeyaml.parser.ParserImpl.peekEvent(ParserImpl.java:158)       11:57:24.168 [DEBUG] [TestEventLogger] at org.yaml.snakeyaml.parser.ParserImpl.checkEvent(ParserImpl.java:143)       11:57:24.169 [DEBUG] [TestEventLogger] at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:226)       11:57:24.169 [DEBUG] [TestEventLogger] at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:155)       11:57:24.169 [DEBUG] [TestEventLogger] at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:231)       11:57:24.171 [DEBUG] [TestEventLogger] at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:155)       11:57:24.171 [DEBUG] [TestEventLogger] at org.yaml.snakeyaml.composer.Composer.composeDocument(Composer.java:122)       11:57:24.175 [DEBUG] [TestEventLogger] at org.yaml.snakeyaml.composer.Composer.getNode(Composer.java:84)       11:57:24.176 [DEBUG] [TestEventLogger] at org.yaml.snakeyaml.constructor.BaseConstructor.getData(BaseConstructor.java:104)       11:57:24.176 [DEBUG] [TestEventLogger] at org.yaml.snakeyaml.Yaml $ 1.next(Yaml.java:502)       11:57:24.176 [DEBUG] [TestEventLogger]在org.springframework.beans.factory.config.YamlProcessor.process(YamlProcessor.java:160)       11:57:24.176 [DEBUG] [TestEventLogger]在org.springframework.beans.factory.config.YamlProcessor.process(YamlProcessor.java:138)       11:57:24.176 [DEBUG] [TestEventLogger]在org.springframework.boot.env.YamlPropertySourceLoader $ Processor.process(YamlPropertySourceLoader.java:100)       11:57:24.181 [DEBUG] [TestEventLogger]在org.springframework.boot.env.YamlPropertySourceLoader.load(YamlPropertySourceLoader.java:57)       11:57:24.183 [QUIET] [system.out] 11:57:24.183 [DEBUG] [org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor]   执行测试类   com.distributedfinance.mbi.payment.repository.ExternalAccountTransferRepositorySpecIT       11:57:24.184 [DEBUG] [TestEventLogger]在org.springframework.boot.env.PropertySourcesLoader.load(PropertySourcesLoader.java:126)       11:57:24.184 [DEBUG] [TestEventLogger] at org.springframework.boot.context.config.ConfigFileApplicationListener $ Loader.loadIntoGroup(ConfigFileApplicationListener.java:381)       11:57:24.184 [DEBUG] [TestEventLogger] at org.springframework.boot.context.config.ConfigFileApplicationListener $ Loader.load(ConfigFileApplicationListener.java:369)       11:57:24.184 [DEBUG] [TestEventLogger] at org.springframework.boot.context.config.ConfigFileApplicationListener $ Loader.load(ConfigFileApplicationListener.java:339)       11:57:24.184 [DEBUG] [TestEventLogger] at org.springframework.boot.context.config.ConfigFileApplicationListener.addPropertySources(ConfigFileApplicationListener.java:174)       11:57:24.185 [DEBUG] [TestEventLogger] at org.springframework.boot.context.config.ConfigFileApplicationListener.onApplicationEnvironmentPreparedEvent(ConfigFileApplicationListener.java:144)       11:57:24.185 [DEBUG] [TestEventLogger] at org.springframework.boot.context.config.ConfigFileApplicationListener.onApplicationEnvironmentPreparedEvent(ConfigFileApplicationListener.java:137)       11:57:24.185 [DEBUG] [TestEventLogger] at org.springframework.boot.context.config.ConfigFileApplicationListener.onApplicationEvent(ConfigFileApplicationListener.java:126)       11:57:24.185 [DEBUG] [TestEventLogger]在org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:151)       11:57:24.185 [DEBUG] [TestEventLogger] at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:128)       11:57:24.186 [DEBUG] [TestEventLogger] at org.springframework.boot.context.event.EventPublishingRunListener.publishEvent(EventPublishingRunListener.java:100)       11:57:24.186 [DEBUG] [TestEventLogger] at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:59)       11:57:24.186 [DEBUG] [TestEventLogger]在org.springframework.boot.SpringApplication.run(SpringApplication.java:285)       11:57:24.186 [DEBUG] [TestEventLogger] at org.springframework.boot.test.SpringApplicationContextLoader.loadContext(SpringApplicationContextLoader.java:103)       11:57:24.186 [DEBUG] [TestEventLogger] at org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:68)       11:57:24.187 [DEBUG] [TestEventLogger] at org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:86)       11:57:24.187 [DEBUG] [TestEventLogger] ...... 24更多

    1. 为什么是应用程序。配置为尝试两种身份验证方法?
    2. 应如何配置?
    3. Spring Boot自动配置中有哪些内容可以控制它吗?
    4. enter image description here

1 个答案:

答案 0 :(得分:5)

肯定错误的是在UsernamePasswordAuthenticationFilter之前执行AnonymousAuthenticationFilter(检查默认顺序here

我欠你的解释是为什么在你的情况下这样配置,但我会回答这个。

  
      
  1. 为什么是应用程序。配置为尝试两种身份验证方法?
  2.   

匿名过滤器必须在任何身份验证尝试之后执行,它的作用是将AuthenticationToken放在SecurityContextHolder中(如果还没有人)(这意味着所有身份验证尝试失败)。

Spring这样做有一个更一致的处理身份验证令牌的方式,否则它应该询问SecurityContextHolder.getAuthentication!= null是否会使授权机制复杂化,例如询问用户的角色。

从春天documentation

  

请注意,“匿名身份验证”的用户与未经身份验证的用户之间没有真正的概念差异。 Spring Security的匿名身份验证只是为您提供了一种更方便的方法来配置访问控制属性。例如,调用servlet API调用(例如getCallerPrincipal)仍将返回null,即使SecurityContextHolder中实际存在匿名身份验证对象。

     

如果类知道SecurityContextHolder始终包含Authentication对象,则可以更健壮地编写类,并且永远不会为null。

发生的事情是您向端点发出请求,但未经过身份验证需要进行身份验证,但您在请求中包含了凭据。

  1. 使用凭据但whitout授权标头
  2. 请求/ securedEndpoint
  3. 执行了BasicAuthenticationFilter,但没有授权标头,因此无法对用户进行身份验证。
  4. 执行AnonymousAuthenticationFilter并将AnonymousToken放入SecurityContextHolder。
  5. 授权机制抛出异常,因为请求尝试获取安全资源。
  6. ExceptionTranslationFilter捕获此异常并调用AuthenticationEntryPoint
  7. AuthenticationEntryPoint重定向到/ login
  8. 执行UsernamePassordAuthenticationFilter并成功验证您的用户。
  9. AnonymousAuthenticationFilter再次执行,但是在SecurityContextHolder alredy中有一个身份验证,它没有做任何事情。
  10. 授权机制允许用户获取资源。
  11. 如果您需要无状态/无会话后端,并且您要在每个请求中发送凭据,则必须配置UsernamePasswordAuthenticationFilter以在所有请求(/ )或所有安全端点(/ secure)中执行/ )。不需要BasicAuthenticationFilter,但您可以使用过滤器。

    提示:您可以使用JWT进行无状态身份验证。

    <强>更新

    Spring boot

    中自定义您的安全配置
      

    默认安全配置在SecurityAutoConfiguration和从那里导入的类中实现(用于Web安全的SpringBootWebSecurityConfiguration和用于身份验证配置的AuthenticationManagerConfiguration,这也与非Web应用程序相关)。要在Web应用程序中完全关闭Boot默认配置,您可以添加带有@EnableWebSecurity的bean。 要自定义它,通常使用WebSecurityConfigurerAdapter类型的外部属性和bean(例如,添加基于表单的登录)。 Spring Boot samples中有几个安全的应用程序可以帮助您开始使用常见的用例。