Java Spring启动:电子邮件验证令牌空错误

Java Spring启动:电子邮件验证令牌空错误,java,spring-boot,spring-mvc,thymeleaf,email-verification,Java,Spring Boot,Spring Mvc,Thymeleaf,Email Verification,我正在开发一个JavaSpringBootWeb应用程序,目前正在开发的功能是用户的“重置密码”功能。它类似于我已经成功创建的一个功能,即“注册用户”功能。但是,由于我不知道的原因,“注册用户”功能正在工作,但由于电子邮件验证令牌为空,“重置密码”功能无法工作。这里首先是注册用户的相关控制器: @RequestMapping(value="/register", method=RequestMethod.GET) ModelAndView register(M

我正在开发一个JavaSpringBootWeb应用程序,目前正在开发的功能是用户的“重置密码”功能。它类似于我已经成功创建的一个功能,即“注册用户”功能。但是,由于我不知道的原因,“注册用户”功能正在工作,但由于电子邮件验证令牌为空,“重置密码”功能无法工作。这里首先是注册用户的相关控制器:

    @RequestMapping(value="/register", method=RequestMethod.GET)
    ModelAndView register(ModelAndView modelAndView) throws FileNotFoundException {
        SiteUser user = new SiteUser(); 
        modelAndView.getModel().put("user", user);
        modelAndView.setViewName("app.register");
        return modelAndView;
    }
    
    
    @RequestMapping(value="/register", method=RequestMethod.POST)
    ModelAndView register(ModelAndView modelAndView, @ModelAttribute(value="user") @Valid SiteUser user, BindingResult result) {
        modelAndView.setViewName("app.register");
        
        if(!result.hasErrors()) {
            userService.register(user);
            String token = userService.createEmailVerificationTokenRegister(user).toString();
            emailService.sendVerificationEmailRegister(user.getEmail(), token);
            modelAndView.setViewName("redirect:/verifyEmail");
        }
        

        return modelAndView;
    }

    @RequestMapping("/confirmRegister")
    ModelAndView registrationConfirmed(ModelAndView modelAndView, @RequestParam("t") String tokenString) {
        
        VerificationToken token = userService.getVerificationToken(tokenString);
        
        System.out.println("verification token " + token);
        
        if(token == null) {
            modelAndView.setViewName("redirect:/invalidUser");
            userService.deleteToken(token);
            return modelAndView;
        }
        
        Date expiryDate = token.getExpiryDate();
        
        if(expiryDate.before(new Date())) {
            modelAndView.setViewName("redirect:/expiredToken");
            userService.deleteToken(token);
            return modelAndView;
        }
        
        SiteUser user = token.getUser();
        
        if (user == null) {
            modelAndView.setViewName("redirect:/invalidUser");
            userService.deleteToken(token);
            return modelAndView;
        }
        
        userService.deleteToken(token);
        user.setEnabled(true);
        userService.save(user);
        
        modelAndView.getModel().put("message", registrationConfirmedMessage);
        modelAndView.setViewName("app.message");
        return modelAndView;
    }
请注意,我也将“token”打印到System.out,在本例中,我获得了一个值,该操作成功。接下来,我尝试使用几乎相同的方法实现“重置密码”功能。以下是控制器:

    @RequestMapping(value="/forgotPassword", method=RequestMethod.GET)
    ModelAndView displayResetPassword(ModelAndView modelAndView, SiteUser user) {
        modelAndView.getModel().put("user", user);
        //modelAndView.addObject("user", user);
        modelAndView.setViewName("app.forgotPassword");
        //System.out.println("*********** GET **********");
        return modelAndView;
    }

    @RequestMapping(value="/forgotPassword", method=RequestMethod.POST)
    ModelAndView forgotUserPassword(ModelAndView modelAndView, @ModelAttribute(value="user") SiteUser user) {
        SiteUser existingUser = userRepo.findByEmail(user.getEmail());
        
        //System.out.println(user.getEmail());
        //userEmail=existingUser.getEmail();
        //userPW=existingUser.getPassword();
        //System.out.println(userEmail);
        //System.out.println(userPW);
        
        System.out.println(existingUser.getEmail());
        
        
        if (existingUser.getEmail() == null)
        {
            modelAndView.setViewName("redirect:/invalidUser");
            System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&& if");
        }
        
        else {
            System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&& else");
            String token = userService.createEmailVerificationTokenForgotPassword(existingUser).toString();

            emailService.sendVerificationEmailForgotPassword(existingUser.getEmail(), token);
            modelAndView.setViewName("redirect:/verifyEmail");
        }
        
        return modelAndView;
    }

    @RequestMapping("/confirmReset")
    ModelAndView confirmReset(ModelAndView modelAndView, @RequestParam("t") String tokenString) {
        
        System.out.println("here");
        
        VerificationToken token = userService.getVerificationToken(tokenString);
        
        System.out.println("verification token " + token);
        
        System.out.println("not here");
        
        if(token == null) {
            modelAndView.setViewName("redirect:/invalidUser");
            userService.deleteToken(token);
            System.out.println("*************** ONE ************");
            return modelAndView;
        }
        
        Date expiryDate = token.getExpiryDate();
        
        if(expiryDate.before(new Date())) {
            modelAndView.setViewName("redirect:/expiredToken");
            userService.deleteToken(token);
            System.out.println("*************** TWO ************");
            return modelAndView;
        }
        
        SiteUser user = token.getUser();
        
        System.out.println("************ USER IS HERE: " + user);
        
        if (user == null) {
            modelAndView.setViewName("redirect:/invalidUser");
            userService.deleteToken(token);
            System.out.println("*************** THREE ************");
            return modelAndView;
        }
        
        user.setEnabled(true);
        userRepo.save(user);
        modelAndView.addObject("user", user);
        modelAndView.addObject("email", user.getEmail());
        modelAndView.setViewName("redirect:/resetPassword");
        userService.deleteToken(token);
        
        return modelAndView;
    }
当我尝试将“token”打印到System.out时,这里的区别在于该值为null。我不明白这是怎么回事,因此我无法重置密码,因为这一点

为了更好地衡量,这里还有VerificationToken类变量,没有显示getter/setter:

@Entity
@Table(name="Verification")
public class VerificationToken {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="id")
    private Long id;
    
    @Column(name="token")
    private String token;
    
    @OneToOne(targetEntity=SiteUser.class) // for every user, there's 1 verification token
    @JoinColumn(name="user_id", nullable=false) // foreign key to users table
    private SiteUser user;
    
    @Column(name="expiry_date")
    @Temporal(TemporalType.TIMESTAMP)
    private Date expiryDate;
    
    @Column(name="token_type")
    @Enumerated(EnumType.STRING)
    private TokenType tokenType;
...
}
以及发送到用户电子邮件的实际email.html文件。首先,forgotPassword.html,这当然不起作用:

<!DOCTYPE html>
<html>

<th:block xmlns:th="http://www.thymeleaf.org">

<p>Please click <a th:href="@{${url} + '/confirmReset?t=' + ${token}}">here</a> to verify your email address and reset your password.</p>
<!-- @{} is a thymeleaf expression -->
</th:block>

</html>

是否有人看到可能发生的情况以及令牌为何为空?

我想知道thymeleaf如何解析属性${url}和${token}。通常,您应该在forgotUserPassword方法中生成令牌后将其传递给视图。如下所示:modelAndView.addObject(“token”,token);
<!DOCTYPE html>
<html>

<th:block xmlns:th="http://www.thymeleaf.org">


<p>Thank you for registering for the bcoreHW site!</p>
<p>Please click <a th:href="@{${url} + '/confirmRegister?t=' + ${token}}">here</a> to verify your email address.</p>
<!-- @{} is a thymeleaf expression -->
</th:block>

</html>
20-10-15 00:07:54.287 DEBUG 69549 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : POST "/forgotPassword", parameters={masked}
2020-10-15 00:07:54.288 DEBUG 69549 --- [nio-8080-exec-2] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to bcoreHW.controllers.AuthController#forgotUserPassword(ModelAndView, SiteUser)
2020-10-15 00:07:54.378 DEBUG 69549 --- [nio-8080-exec-2] org.hibernate.SQL                        : select siteuser0_.user_id as user_id1_3_, siteuser0_.email as email2_3_, siteuser0_.enabled as enabled3_3_, siteuser0_.password as password4_3_, siteuser0_.role as role5_3_ from users siteuser0_ where siteuser0_.email=?
Hibernate: select siteuser0_.user_id as user_id1_3_, siteuser0_.email as email2_3_, siteuser0_.enabled as enabled3_3_, siteuser0_.password as password4_3_, siteuser0_.role as role5_3_ from users siteuser0_ where siteuser0_.email=?
admin@admin.com
&&&&&&&&&&&&&&&&&&&&&&&&& else
2020-10-15 00:07:54.402 DEBUG 69549 --- [nio-8080-exec-2] org.hibernate.SQL                        : select next_val as id_val from hibernate_sequence for update
Hibernate: select next_val as id_val from hibernate_sequence for update
2020-10-15 00:07:54.403 DEBUG 69549 --- [nio-8080-exec-2] org.hibernate.SQL                        : update hibernate_sequence set next_val= ? where next_val=?
Hibernate: update hibernate_sequence set next_val= ? where next_val=?
2020-10-15 00:07:54.417 DEBUG 69549 --- [nio-8080-exec-2] org.hibernate.SQL                        : insert into forgot_password (expiry_date, token, token_type, user_id, id) values (?, ?, ?, ?, ?)
Hibernate: insert into forgot_password (expiry_date, token, token_type, user_id, id) values (?, ?, ?, ?, ?)
2020-10-15 00:07:54.425 DEBUG 69549 --- [nio-8080-exec-2] o.s.web.servlet.view.RedirectView        : View name 'redirect:', model {}
2020-10-15 00:07:54.426 DEBUG 69549 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : Completed 302 FOUND
2020-10-15 00:07:54.434 DEBUG 69549 --- [nio-8080-exec-6] o.s.web.servlet.DispatcherServlet        : GET "/verifyEmail", parameters={}
2020-10-15 00:07:54.434 DEBUG 69549 --- [nio-8080-exec-6] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to bcoreHW.controllers.AuthController#verifyEmail()
2020-10-15 00:07:54.436 DEBUG 69549 --- [nio-8080-exec-6] o.s.w.s.v.ContentNegotiatingViewResolver : Selected 'text/html' given [text/html, application/xhtml+xml, image/avif, image/webp, image/apng, application/xml;q=0.9, application/signed-exchange;v=b3;q=0.9, */*;q=0.8]
2020-10-15 00:07:54.436 DEBUG 69549 --- [nio-8080-exec-6] o.s.web.servlet.view.tiles3.TilesView    : View name 'app.verifyEmail', model {}
2020-10-15 00:07:54.507 DEBUG 69549 --- [nio-8080-exec-6] o.s.web.servlet.DispatcherServlet        : Completed 200 OK
2020-10-15 00:07:54.528 DEBUG 69549 --- [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet        : GET "/css/bootstrap.min.css", parameters={}
2020-10-15 00:07:54.528 DEBUG 69549 --- [nio-8080-exec-7] o.s.web.servlet.DispatcherServlet        : GET "/css/main.css", parameters={}
2020-10-15 00:07:54.528 DEBUG 69549 --- [nio-8080-exec-5] o.s.web.servlet.DispatcherServlet        : GET "/js/bootstrap.min.js", parameters={}
2020-10-15 00:07:54.529 DEBUG 69549 --- [nio-8080-exec-8] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped to ResourceHttpRequestHandler ["classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/", "/"]
2020-10-15 00:07:54.529 DEBUG 69549 --- [nio-8080-exec-7] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped to ResourceHttpRequestHandler ["classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/", "/"]
2020-10-15 00:07:54.529 DEBUG 69549 --- [nio-8080-exec-5] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped to ResourceHttpRequestHandler ["classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/", "/"]
2020-10-15 00:07:54.529 DEBUG 69549 --- [nio-8080-exec-9] o.s.web.servlet.DispatcherServlet        : GET "/img/bcore-bride+AI.png", parameters={}
2020-10-15 00:07:54.532 DEBUG 69549 --- [nio-8080-exec-7] o.s.web.servlet.DispatcherServlet        : Completed 200 OK
2020-10-15 00:07:54.532 DEBUG 69549 --- [nio-8080-exec-9] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped to ResourceHttpRequestHandler ["classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/", "/"]
2020-10-15 00:07:54.532 DEBUG 69549 --- [nio-8080-exec-5] o.s.web.servlet.DispatcherServlet        : Completed 200 OK
2020-10-15 00:07:54.533 DEBUG 69549 --- [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet        : Completed 200 OK
2020-10-15 00:07:54.535 DEBUG 69549 --- [nio-8080-exec-9] o.s.web.servlet.DispatcherServlet        : Completed 200 OK
2020-10-15 00:07:57.309 DEBUG 69549 --- [io-8080-exec-10] o.s.web.servlet.DispatcherServlet        : GET "/confirmReset?t=6e374e4e-0113-4fae-92f7-e8b5c97755d9", parameters={masked}
2020-10-15 00:07:57.309 DEBUG 69549 --- [io-8080-exec-10] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to bcoreHW.controllers.AuthController#confirmReset(ModelAndView, String)
here
2020-10-15 00:07:57.315 DEBUG 69549 --- [io-8080-exec-10] org.hibernate.SQL                        : select verificati0_.id as id1_4_, verificati0_.expiry_date as expiry_d2_4_, verificati0_.token as token3_4_, verificati0_.token_type as token_ty4_4_, verificati0_.user_id as user_id5_4_ from verification verificati0_ where verificati0_.token=?
Hibernate: select verificati0_.id as id1_4_, verificati0_.expiry_date as expiry_d2_4_, verificati0_.token as token3_4_, verificati0_.token_type as token_ty4_4_, verificati0_.user_id as user_id5_4_ from verification verificati0_ where verificati0_.token=?
verification token null
not here
2020-10-15 00:07:57.322 DEBUG 69549 --- [io-8080-exec-10] .m.m.a.ExceptionHandlerExceptionResolver : Using @ExceptionHandler bcoreHW.controllers.GlobalExceptionHandler#defaultErrorHandler(HttpServletRequest, Exception)
2020-10-15 00:07:57.322 DEBUG 69549 --- [io-8080-exec-10] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.dao.InvalidDataAccessApiUsageException: Entity must not be null!; nested exception is java.lang.IllegalArgumentException: Entity must not be null!] to ModelAndView [view="app.exception"; model={message=An error occurred., url=http://localhost:8080/confirmReset, exception=org.springframework.dao.InvalidDataAccessApiUsageException: Entity must not be null!; nested exception is java.lang.IllegalArgumentException: Entity must not be null!}]
2020-10-15 00:07:57.322 DEBUG 69549 --- [io-8080-exec-10] o.s.web.servlet.DispatcherServlet        : Using resolved error view: ModelAndView [view="app.exception"; model={message=An error occurred., url=http://localhost:8080/confirmReset, exception=org.springframework.dao.InvalidDataAccessApiUsageException: Entity must not be null!; nested exception is java.lang.IllegalArgumentException: Entity must not be null!}]
2020-10-15 00:07:57.323 DEBUG 69549 --- [io-8080-exec-10] o.s.w.s.v.ContentNegotiatingViewResolver : Selected 'text/html' given [text/html, application/xhtml+xml, image/avif, image/webp, image/apng, application/xml;q=0.9, application/signed-exchange;v=b3;q=0.9, */*;q=0.8]
2020-10-15 00:07:57.323 DEBUG 69549 --- [io-8080-exec-10] o.s.web.servlet.view.tiles3.TilesView    : View name 'app.exception', model {message=An error occurred., url=http://localhost:8080/confirmReset, exception=org.springframework.dao.InvalidDataAccessApiUsageException: Entity must not be null!; nested exception is java.lang.IllegalArgumentException: Entity must not be null!}
2020-10-15 00:07:57.456 DEBUG 69549 --- [io-8080-exec-10] o.s.web.servlet.DispatcherServlet        : Completed 404 NOT_FOUND