【问题标题】:NoOpPasswordEncoder is not working, returns statuscode 200 instead of 401NoOpPasswordEncoder 不工作,返回状态码 200 而不是 401
【发布时间】:2021-04-04 16:04:13
【问题描述】:

我正在尝试通过 Spring Boot 学习 Spring Security 的基础知识,我创建了一个项目,其中还包括 postgresql 设置。 Postgresql 部分按预期工作。

问题是,在我通过正确的凭据访问安全端点后,我只是尝试使用正确的用户名和错误的密码进行访问,并期待 401 错误,但返回 200。并且还返回到端点的内容。

  • 如果我使用username: dummy_userpassword: 12345 执行基本身份验证请求,则响应为 401 UnAuthorized
  • 如果我使用username: dummy_userpassword: 1234 进行基本身份验证请求,则响应为 200
  • 如果我使用username: dummy_userpassword: 1234 进行基本身份验证请求,则响应为 200
  • 在响应 200 之后,如果我使用 username: dummy_userpassword: 12345 进行基本身份验证请求,则响应为 200

在运行项目之前,我只是添加了一个虚拟用户:

INSERT INTO test_users (username,password) VALUES ('dummy_user','1234');

DTO 很简单:

@Entity
@Table(name = "test_users")
public class UserDTO {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(name = "username")
    private String username;

    @Column(name = "password")
    private String password;
  • 配置类:
@Configuration
public class ProjectBeanConfiguration {
    @Bean
    public UserDetailsService userDetailsService(){
       return new PostgresqlUserDetailsService();
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }
}
  • 还有 userDetailsS​​ervice:
public class PostgresqlUserDetailsService implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username){
        Optional<UserDTO> userDTOOptional = userRepository.findUserByUsername(username);
        UserDTO userInDb = userDTOOptional.orElseThrow(() -> new UsernameNotFoundException("Not Found in DB"));
        SecureUser secureUser = new SecureUser(userInDb);
        return secureUser;
    }
}
  • SecureUser 什么都不是,它只是将 UserDTO 映射到 UserDetails:
public class SecureUser  implements UserDetails {

    private final UserDTO userDTO;

    public SecureUser(UserDTO userDTO) {
        this.userDTO = userDTO;
    } 
    // ...
    @Override
    public String getPassword() {
        return userDTO.getPassword();
    }

    @Override
    public String getUsername() {
        return userDTO.getUsername();
    }
    // ...
  • 只有一个控制器:
@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello(){
        return "hello";
    }
}
  • 日志记录:在响应 200 之后,如果我使用用户名:dummy_user 和密码:12345 进行基本身份验证请求,则响应为 200:
020-12-27 21:52:19.711 DEBUG 32988 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /hello at position 1 of 15 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2020-12-27 21:52:19.711 DEBUG 32988 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /hello at position 2 of 15 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2020-12-27 21:52:19.711 DEBUG 32988 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl@8e885cc7: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@8e885cc7: Principal: com...springsecurity.services.SecureUser@49860e95; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: com...springsecurity.services.SecureUser$$Lambda$890/0x0000000800848040@38f11ef2'
2020-12-27 21:52:19.711 DEBUG 32988 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /hello at position 3 of 15 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2020-12-27 21:52:19.711 DEBUG 32988 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /hello at position 4 of 15 in additional filter chain; firing Filter: 'CsrfFilter'
2020-12-27 21:52:19.711 DEBUG 32988 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /hello at position 5 of 15 in additional filter chain; firing Filter: 'LogoutFilter'
2020-12-27 21:52:19.711 DEBUG 32988 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'GET /hello' doesn't match 'POST /logout'
2020-12-27 21:52:19.711 DEBUG 32988 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /hello at position 6 of 15 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2020-12-27 21:52:19.711 DEBUG 32988 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'GET /hello' doesn't match 'POST /login'
2020-12-27 21:52:19.711 DEBUG 32988 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /hello at position 7 of 15 in additional filter chain; firing Filter: 'DefaultLoginPageGeneratingFilter'
2020-12-27 21:52:19.711 DEBUG 32988 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /hello at position 8 of 15 in additional filter chain; firing Filter: 'DefaultLogoutPageGeneratingFilter'
2020-12-27 21:52:19.711 DEBUG 32988 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/hello'; against '/logout'
2020-12-27 21:52:19.711 DEBUG 32988 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /hello at position 9 of 15 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
2020-12-27 21:52:19.711 DEBUG 32988 --- [nio-8080-exec-2] o.s.s.w.a.www.BasicAuthenticationFilter  : Basic Authentication Authorization header found for user 'dummy_user'
2020-12-27 21:52:19.711 DEBUG 32988 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /hello at position 10 of 15 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2020-12-27 21:52:19.712 DEBUG 32988 --- [nio-8080-exec-2] o.s.s.w.s.HttpSessionRequestCache        : saved request doesn't match
2020-12-27 21:52:19.712 DEBUG 32988 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /hello at position 11 of 15 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2020-12-27 21:52:19.712 DEBUG 32988 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /hello at position 12 of 15 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2020-12-27 21:52:19.712 DEBUG 32988 --- [nio-8080-exec-2] o.s.s.w.a.AnonymousAuthenticationFilter  : SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken@8e885cc7: Principal: com...springsecurity.services.SecureUser@49860e95; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: com...springsecurity.services.SecureUser$$Lambda$890/0x0000000800848040@38f11ef2'
2020-12-27 21:52:19.712 DEBUG 32988 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /hello at position 13 of 15 in additional filter chain; firing Filter: 'SessionManagementFilter'
2020-12-27 21:52:19.712 DEBUG 32988 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /hello at position 14 of 15 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2020-12-27 21:52:19.712 DEBUG 32988 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /hello at position 15 of 15 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2020-12-27 21:52:19.712 DEBUG 32988 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /hello; Attributes: [authenticated]
2020-12-27 21:52:19.712 DEBUG 32988 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@8e885cc7: Principal: com...springsecurity.services.SecureUser@49860e95; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: com...springsecurity.services.SecureUser$$Lambda$890/0x0000000800848040@38f11ef2
2020-12-27 21:52:19.712 DEBUG 32988 --- [nio-8080-exec-2] o.s.s.access.vote.AffirmativeBased       : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@5b81c050, returned: 1
2020-12-27 21:52:19.712 DEBUG 32988 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor    : Authorization successful
2020-12-27 21:52:19.712 DEBUG 32988 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor    : RunAsManager did not change Authentication object
2020-12-27 21:52:19.712 DEBUG 32988 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /hello reached end of additional filter chain; proceeding with original chain
2020-12-27 21:52:19.714 DEBUG 32988 --- [nio-8080-exec-2] o.s.s.w.header.writers.HstsHeaderWriter  : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@70616cef
2020-12-27 21:52:19.715 DEBUG 32988 --- [nio-8080-exec-2] o.s.s.w.a.ExceptionTranslationFilter     : Chain processed normally
2020-12-27 21:52:19.716 DEBUG 32988 --- [nio-8080-exec-2] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed

【问题讨论】:

  • 请发布您的安全配置和调试日志,您可以通过关注此帖子stackoverflow.com/a/47729991/1840146获取日志
  • @Toerktumlare 只有一个配置类,即 ProjectBeanConfiguration
  • 您发布的日志不能是您所有请求的调试日志。它太小并且缺少时间戳等。整个日志中只有一个时间戳
  • 另外,在数据库中存储密码时,您需要在密码前加上正在使用的编码器类型。在你的情况下,它是{noop}1234,你可以在这里阅读它docs.spring.io/spring-security/site/docs/5.4.2/reference/html5/…
  • @Ashutosh 每个默认 Spring 安全性将保护所有端点。只要将 Spring 安全性放在类路径 docs.spring.io/spring-security/site/docs/current/reference/… 上,您就可以阅读有关设置的默认配置的更多信息,其中一个配置是 Require an authenticated user for any interaction with the application

标签: spring spring-boot spring-security


【解决方案1】:

根据日志:

SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken@8e885cc7: Principal

这表示当你访问 hello 时,上下文中已经有一个主体。

然后日志告诉我们:

Previously Authenticated

所以我的结论(因为这不是完整的日志)并且我们还没有看到您如何处理您的请求,如下:

// No session established, you provide wrong credentials, you get a 401
 - If I do a basic authentication request with username: dummy_user and password: 12345, response is 401 UnAuthorized

// You authenticate correctly, we establish a session, you get a session cookie
- If I do a basic authentication request with username: dummy_user and password: 1234, response is 200

// You provide the session cookie in your request, we get a 200OK
- If I do a basic authentication request with username: dummy_user and password: 1234, response is 200

// You still provide the session cookie, we get a 200OK 
- After response 200, If I do a basic authentication request with username: dummy_user and password: 12345, response is 200

如果您想确认该理论,您应该在每次登录尝试之间/logout 或删除设置的 cookie。

【讨论】:

  • 我认为,会话 cookie 是原因,谢谢伙计。有趣的一点是我使用邮递员发送请求,因此邮递员以某种方式存储会话!
  • 邮递员总是在每个请求中发送 cookie,这就是为什么除非你明确告诉它不要这样做。
【解决方案2】:

当您第一次使用正确的用户名和密码登录时,Spring Security 将创建一个会话对象并为您提供一个会话 cookie。会话对象是存储信息的对象。当您第一次登录时,它会创建一个表示您已成功登录的身份验证令牌,并将其存储在会话对象中。每次您访问 Web 应用程序上的安全端点时,您都​​会发送会话 cookie。 cookie 将您识别为已被记录。要删除会话 cookie,请转到注销端点 url,这将删除您的会话。

【讨论】:

    猜你喜欢
    • 2019-03-23
    • 2016-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-28
    • 2012-12-29
    • 2018-09-13
    • 1970-01-01
    相关资源
    最近更新 更多