使用 Spring 安全注册创建会话

Posted

技术标签:

【中文标题】使用 Spring 安全注册创建会话【英文标题】:session create using spring security registration 【发布时间】:2020-06-08 01:24:28 【问题描述】:

我正在使用构建https://github.com/Baeldung/spring-security-registration 的文章之后的spring security 进行注册处理。根据本文,html 页面接受输入并将其插入到数据库中。

我正在前端使用 Flutter 应用程序。我希望当用户请求重置密码时,会向用户的电子邮件发送一个链接,当用户单击验证链接时,它将创建一个会话并重定向到应用程序上的 UI 页面编写新密码。当用户输入新密码时,它将更新该用户的密码。

updatePassword.html

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css"/>
    <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"/>
    <style>
.password-verdict
color:#000;


    </style>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
    <script th:src="@/resources/pwstrength.js"></script>
    <title th:text="#message.updatePassword">update password</title>
</head>
<body>
<div sec:authorize="hasAuthority('CHANGE_PASSWORD_PRIVILEGE')">
    <div class="container">
        <div class="row">
            <h1 th:text="#message.resetYourPassword">reset</h1>
            <form>
                <br/>

                <label class="col-sm-2" th:text="#label.user.password">password</label>
                <span class="col-sm-5"><input class="form-control" id="password" name="newPassword" type="password"
                                              value=""/></span>
                <div class="col-sm-12"></div>
                <br/><br/>
                <label class="col-sm-2" th:text="#label.user.confirmPass">confirm</label>
                <span class="col-sm-5"><input class="form-control" id="matchPassword" type="password" value=""/></span>
                <div id="globalError" class="col-sm-12 alert alert-danger" style="display:none"
                     th:text="#PasswordMatches.user">error
                </div>

                <div class="col-sm-12">
                    <br/><br/>
                    <button class="btn btn-primary" type="submit" onclick="savePass()"
                            th:text="#message.updatePassword">submit
                    </button>
                </div>
            </form>

        </div>
    </div>

    <script th:inline="javascript">
var serverContext = [[@/]];

$(document).ready(function () 
    $('form').submit(function(event) 
        savePass(event);
    );

    $(":password").keyup(function()
        if($("#password").val() != $("#matchPassword").val())
            $("#globalError").show().html(/*[[#PasswordMatches.user]]*/);
        else
            $("#globalError").html("").hide();
        
    );

    options = 
            common: minChar:6,
            ui: 
                showVerdictsInsideProgressBar:true,
                showErrors:true,
                errorMessages:
                      wordLength: /*[[#error.wordLength]]*/,

                    
                
        ;
     $('#password').pwstrength(options);
);

function savePass(event)
    event.preventDefault();
    $(".alert").html("").hide();
    $(".error-list").html("");
    if($("#password").val() != $("#matchPassword").val())
        $("#globalError").show().html(/*[[#PasswordMatches.user]]*/);
        return;
    
    var formData= $('form').serialize();
    $.post(serverContext + "user/savePassword",formData ,function(data)
        window.location.href = serverContext + "login?message="+data.message;
    )
    .fail(function(data) 
        if(data.responseJSON.error.indexOf("InternalError") > -1)
            window.location.href = serverContext + "login?message=" + data.responseJSON.message;
        
        else
            var errors = $.parseJSON(data.responseJSON.message);
            $.each( errors, function( index,item )
                $("#globalError").show().html(item.defaultMessage);
            );
            errors = $.parseJSON(data.responseJSON.error);
            $.each( errors, function( index,item )
                $("#globalError").show().append(item.defaultMessage+"<br/>");
            );
        
    );



    </script>
</div>
</body>

</html>

这将创建会话并完美更新密码。 但我想发送一个发布请求和一个 newPassword 以存储在数据库中。但无法创建会话。

Controller.java

@RequestMapping(value = "/user/savePassword", method = RequestMethod.POST)
    @ResponseBody
    public String savePassword(@RequestParam("newPassword") String newPassword) 
        final User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        userService.changeUserPassword(user, newPassword);
        return "Password has been changed successfully. ";
    

这个

final User user = (User) 
SecurityContextHolder.getContext().getAuthentication().getPrincipal();

当我直接从 UI App 中点击 URL 时,没有创建用户的会话。

请告诉我这样做的方法。

【问题讨论】:

【参考方案1】:

很难理解发生了什么错误。如果我理解正确,并且你按照这个例子https://www.baeldung.com/spring-security-registration-i-forgot-my-password是无可挑剔的,那么在从信中检查令牌的时候,你应该已经被授权了。

我猜,应该是这里

public String validatePasswordResetToken(long id, String token) 
    PasswordResetToken passToken = 
      passwordTokenRepository.findByToken(token);
    if ((passToken == null) || (passToken.getUser()
        .getId() != id)) 
        return "invalidToken";
    

    Calendar cal = Calendar.getInstance();
    if ((passToken.getExpiryDate()
        .getTime() - cal.getTime()
        .getTime()) <= 0) 
        return "expired";
    

    User user = passToken.getUser();
    Authentication auth = new UsernamePasswordAuthenticationToken(
      user, null, Arrays.asList(
      new SimpleGrantedAuthority("CHANGE_PASSWORD_PRIVILEGE")));
    SecurityContextHolder.getContext().setAuthentication(auth); // authorization after validation of reset token
    return null;

请提供更多关于您的情况的信息。给我一个完整的例子。或者你只是直接保存密码?

【讨论】:

先生,我正在使用“Flutter”应用程序作为前端。我只想重定向到用户可以输入new-password 的应用页面,但我无法在验证令牌后将信号定向到颤振应用。

以上是关于使用 Spring 安全注册创建会话的主要内容,如果未能解决你的问题,请参考以下文章

会话创建和会话销毁事件中的 Spring 安全访问用户详细信息

Spring Boot 安全性:请求的 url 创建了不需要的 redis 会话

没有会话或数据库的安全 CSRF 保护?

Spring Security用户手动登录会话由管理员创建,无需密码

Spring 社交和会话注册表

Spring Security - 公共页面重定向到使用无效会话 ID 登录