如何使用默认类从 JSON 登录尝试中读取用户凭据?

Posted

技术标签:

【中文标题】如何使用默认类从 JSON 登录尝试中读取用户凭据?【英文标题】:How can I read the user credentials from a JSON login attempt using default classes? 【发布时间】:2020-03-18 18:02:09 【问题描述】:

我正在关注Implementing JWT Authentication on Spring Boot APIs 上的教程,在作者的 JWTAuthenticationFilter 类的关键部分(听起来就是这样),他从 POST 请求的 JSON 正文中检索用户名和密码到登录端点.

因此,使用 curl 或 Postman 或其他东西,您可以使用包含 "username":"joe", "password":"pass" 之类的请求正文 POST 到 /login。

作者的身份验证过滤器使用此方法将此 JSON 映射到 ApplicationUser 实例:

@Override
public Authentication attemptAuthentication(HttpServletRequest req,
                                            HttpServletResponse res) throws AuthenticationException 
    try 
        ApplicationUser creds = new ObjectMapper()
                .readValue(req.getInputStream(), ApplicationUser.class);

        return authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                        creds.getUsername(),
                        creds.getPassword(),
                        new ArrayList<>())
        );
     catch (IOException e) 
        throw new RuntimeException(e);
    

足够好,但要做到这一点,他创建了一个自定义类 ApplicationUser 以及一个客户 UserDetailsS​​ervice、一个 UserController 和一个 ApplicationUserRepository,所有这些都与他自己的特殊内存数据库后端一起工作。在我真正的 Spring Boot 应用程序中,我使用默认数据库模式并让 Spring Boot 通过 JDBC 对用户进行身份验证。它适用于表单身份验证。这是我的 WebSecurityConfigurerAdapter 中的一点:

    @Autowired
    private DataSource dataSource;

    @Override
    public void configure(AuthenticationManagerBuilder builder) throws Exception 
        builder .jdbcAuthentication()
                .dataSource(dataSource);
    

所以我的问题是,attemptAuthentication 方法需要如何从教程的代码中更改?我猜测默认实现可能是User.class,并尝试将其插入导入“creds”的表达式中,如下所示:

User creds = new ObjectMapper().readValue(request.getInputStream(), User.class);

那没用。我得到了这个例外:

webapp_1  | 2019-11-22 15:54:43.234  WARN 1 --- [nio-8080-exec-2] n.j.w.g.config.JWTAuthenticationFilter   : inputstream: org.apache.catalina.connector.CoyoteInputStream@1477c9d5
webapp_1  | 2019-11-22 15:54:43.298 ERROR 1 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
webapp_1  |
webapp_1  | java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `org.springframework.security.core.userdetails.User` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

我不想只是深入研究User 的子类,因为我实际上什至不知道它是否是正确的类,或者我什至在这里是否需要它。我可以以其他方式从我的 JSON POST 中提取usernamepassword,也许绕过ObjectMapper() 的使用?或者我应该在这里创建一个私有内部类?总而言之,问题是:在 Spring Boot 中使用默认的基于 JDBC 的用户实现时,如何才能最好地适应这种“attemptAuthentication”方法?

【问题讨论】:

【参考方案1】:

我找到了一个可行的解决方案,尽管我仍然认为必须有一种更优雅的方式来做到这一点。我所做的是定义一个静态内部类LoginAttempt 并使用ObjectMapper 来读取JSON 作为它的一个实例。

我发现如果没有 static 修饰符,Jackson 无法反序列化内部类(请参阅 this question),但使用“static”它可以工作。

来自JWTAuthenticationFilter的相关代码为:

static class LoginAttempt 
    private String username;
    private String password;
    public LoginAttempt() 
    public String getUsername()  return username; 
    public String getPassword()  return password; 
    public void setUsername(String username)  this.username = username; 
    public void setPassword(String password)  this.password = password; 


@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException 
    try 
        LoginAttempt creds = new ObjectMapper().readValue(request.getInputStream(), LoginAttempt.class);
        return authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                        creds.getUsername(),
                        creds.getPassword(),
                        new ArrayList<>()
                )
        );
     catch( IOException e ) 
        throw new RuntimeException(e);
    

【讨论】:

以上是关于如何使用默认类从 JSON 登录尝试中读取用户凭据?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 json 的帮助下使用 PHP、MySql 在 android 中验证用户登录凭据

如何使用下面的类从web服务中动态读取下面给出的JSON数据,并为收到的数据创建水平列表视图。

如果 maxSessionsPreventsLogin 设置为 true 并且某些使用我的登录凭据的用户尝试登录,如何在我的 thymelaf 登录页面中显示错误?

Redux,Fetch,如何捕获 json()

如何通过使用 c# 传递凭据在服务器上创建文件夹

Windows 凭据提供程序远程登录