Spring安全性:新的用户工作流



我是Spring security的新手。

我已经创建了一个用户登录的自定义表单,然后,在成功登录后,用户继续他/她的预期网页。我的实现是标准的,它工作。

我的问题是。

  • 用户想要访问页面mywebpage.html
  • 用户未登录。的用户被重定向(由Spring Security)到登录页面。
  • 用户没有账户。
  • 用户单击createAccount链接并通过标准MVC协议进入注册页面。

我现在如何从Spring Security获得用户最初预期的目的地(mywebpage.html),这样我就可以在他/她创建帐户后将用户重定向到该页面?

为记录,security.xml

	<http auto-config="true">
	<intercept-url pattern="/login"  access="permitAll()" />
	<intercept-url pattern="/flow-entry.html" access="hasRole('ROLE_USER')"/>
		<form-login
         login-page="/login"
         authentication-failure-url="/login?error=true" />
 
      <logout logout-success-url="/login" />
</http>

登录表单

   <form name='f' action="login" method='POST'>
      <table style="text-align:left" class="w3-table" >
      <tr style="text-align:center;color:red" th:if="${loginresponse}">
            <td colspan="2" style="text-align:center" th:text="#{${loginresponse}}">  </td>
         </tr>
         <tr>
            <td th:text="#{label.emaillogin}"></td>
            <td><input type="text" name="username" value=''/></td>
         </tr>
         <tr>
            <td th:text="#{label.password}">Password:</td>
            <td><input type="password" name="password" /></td>
         </tr>
         <tr>
            <td colspan="2" style="text-align:center"><input name="submit" type="submit" class="w3-btn w3-blue w3-hover-aqua w3-round-large" th:value="#{label.ok}" /></td>
            <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/> 
         </tr>
         <tr style="text-align:center">
            <td colspan="2" style="text-align:center">  <a href="./register"><span th:text="#{label.register}"></span></a> </td>
         </tr>
      </table>
  </form>

控制器方法。我需要原本打算的网页在这个方法

    @RequestMapping(value = "/doRegistration", method=RequestMethod.POST)
public ModelAndView doRegistration(ModelAndView mv, HttpServletRequest request) 
{
    mv.setViewName("register");
    SSm.getLogger().debug("registering new user");
    String email = request.getParameter("username");
    String email1 = request.getParameter("username1");
    if(email.equals(email1))
    {
        if(email.contains("@")&&email.contains("."))
        {
            SSm.getLogger().debug("got legit email");
            String password = request.getParameter("password");
            String password1 = request.getParameter("password1");
            if(password.equals(password1))
            {
                SSm.getLogger().debug("ready to login");
         I NEED USERS ORIGINALLY INTENDED DESTINATION RIGHT HERE SO I CAN SET THE VIEW
            }
            else
            {
                mv.setViewName("register");
                mv.addObject("loginresponse", "message.passwordmismatch");
            }
        }
        else
        {
            mv.setViewName("register");
            mv.addObject("loginresponse", "message.invalidemail");
        }
    }
    else
    {
        mv.setViewName("register");
        mv.addObject("loginresponse", "message.emailmismatch");
    }

    return mv;
}

你可以使用SavedRequestAwareAuthenticationSuccessHandler

当一个未经授权的请求到达ExceptionTranslationFilter时,将创建一个httpessionrequestcache类的RequestCache,并将原始请求保存在其上。

这样,如果你不设置alwaysUseDefaultTargetUrl为true, httpRequest将被重建并用作目标url,而正确的登录执行。

所以,尝试@Autowire(我使用@Resource代替,因为我在我的安全配置中有多个AuthenticationManager和AuthenticationSuccessHandler)在控制器中的AuthenticationSuccessHandler并像这样调用determineTargetUrl():

我做了一些修改,例如使用@Valid注释并实现Validator来验证注册表单

Security.xml

<beans:bean id="savedRequestSuccesHandler" 
    class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
    <beans:property name="defaultTargetUrl" value="/zone4/secured/securedPage.htm" />   
</beans:bean>
<security:http pattern="/zone4/**" use-expressions="true" authentication-manager-ref="mainAuthenticationManager">
    <security:intercept-url pattern="/zone4/simple/**"  access="permitAll()" />
    <security:intercept-url pattern="/zone4/secured/**" access="isAuthenticated()"/>
    <security:form-login 
        login-page="/zone4/simple/login.htm" 
        authentication-failure-url="/login.htm?error=true" 
        authentication-success-handler-ref="savedRequestSuccesHandler" 
        username-parameter="email" 
        password-parameter="password"
        login-processing-url="/zone4/secured/performLogin.htm" 
    />
    <security:logout 
        logout-url="/zone4/secured/performLogout.htm" 
        logout-success-url="/zone4/simple/login.htm" />
    <security:csrf disabled="true"/>
</security:http>

控制器:

/**
 * 
 */
package com.eej.ssba2.controller.test;
import java.io.IOException;
import java.util.Arrays;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.eej.ssba2.model.test.zone4.RegisterModel;
import com.eej.ssba2.model.test.zone4.RegisterModelValidator;
/**
 *
 */
@Controller
@RequestMapping("/zone4")
public class Zone4TestController {
    private Logger logger = Logger.getLogger(this.getClass());
    @Resource(name="mainAuthenticationManager")
    private AuthenticationManager authenticationManager;
    @Resource(name="savedRequestSuccesHandler")
    private SavedRequestAwareAuthenticationSuccessHandler successHandler;
    @RequestMapping("/simple/unsecuredPage.htm")
    public String unsecuredPage(){
        return "simple/unsecuredPage";
    }
    @RequestMapping("/secured/securedPage.htm")
    public String securedPage1(){
        return "simple/secured/securedPage";
    }
    @RequestMapping("/secured/securedPage2.htm")
    public String securedPage2(){
        return "simple/secured/securedPage2";
    }
    @RequestMapping("/secured/securedPage3.htm")
    public String securedPage3(){
        return "simple/secured/securedPage3";
    }
    @RequestMapping("/simple/login.htm")
    public String login(){
        return "simple/login/login";
    }
    @RequestMapping(value="/simple/register.htm", method=RequestMethod.GET)
    public String register(ModelMap model){
        logger.debug("Entrada en register.htm");
        if(!model.containsAttribute("registerModel")){
            model.addAttribute("registerModel", new RegisterModel());
        }
        return "simple/login/register";
    }
    @RequestMapping(value="/simple/register.htm", method=RequestMethod.POST)
    public String register(
            HttpServletRequest request, HttpServletResponse response, 
            @Valid RegisterModel registerModel, ModelMap model, BindingResult bindingResult){
        logger.info("entrada en register");
        RegisterModelValidator userValidator = new RegisterModelValidator();
        userValidator.validate(registerModel, bindingResult);
        if(bindingResult.hasErrors()){
            logger.info("BindingResult has errors: " + bindingResult.getAllErrors());
            model.addAttribute("errors", bindingResult.getAllErrors());
            model.addAttribute("registerModel", registerModel);
            return "simple/login/register";
        }
        // Your user register business
        Authentication authenticated = null;
        /*
         * If the user is created at this time due to your business logic, you could authenticate it directly 
         * through the manager
         *
        authenticated = 
                this.authenticationManager.authenticate(
                        new UsernamePasswordAuthenticationToken(
                            registerModel.getMail1(), 
                            registerModel.getPassword1()                        
                        )
                );
        */
        authenticated = new UsernamePasswordAuthenticationToken(
                    registerModel.getMail1(), 
                    registerModel.getPassword1(), 
                    Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"))
                );
        SecurityContextHolder.getContext().setAuthentication(authenticated);
        try {
            this.successHandler.onAuthenticationSuccess(request, response, authenticated);
        } catch (ServletException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
}

注册模型bean:

package com.eej.ssba2.model.test.zone4;
import java.io.Serializable;
import javax.validation.Valid;
import javax.validation.constraints.Pattern;
import org.apache.log4j.Logger;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import com.eej.ssba2.ApplicationVersion;
/**
 * 
 *
 */
public class RegisterModel implements Serializable{
    private Logger logger = Logger.getLogger(this.getClass());
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    @NotEmpty
    @Pattern(regexp = "^[_A-Za-z0-9-\+]+(\.[_A-Za-z0-9-]+)*" +
            "@[A-Za-z0-9-]+(\.[A-Za-z0-9]+)*(\.[A-Za-z]{2,})$|")
    public String mail1;
    @NotEmpty
    @Pattern(regexp = "^[_A-Za-z0-9-\+]+(\.[_A-Za-z0-9-]+)*" +
            "@[A-Za-z0-9-]+(\.[A-Za-z0-9]+)*(\.[A-Za-z]{2,})$|")
    public String mail2;
    @NotEmpty
    public String password1;
    @NotEmpty
    public String password2;
    // getters and setters  
}

我用来验证模型中的字段的Validator实现:

package com.eej.ssba2.model.test.zone4;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
    public class RegisterModelValidator implements Validator {
        @Override
        public boolean supports(Class<?> arg0) {
            return RegisterModel.class.equals(arg0);
        }
        @Override
        public void validate(Object target, Errors errors) {
            RegisterModel user = (RegisterModel) target;
            if(!user.getMail1().equals(user.getMail2())){
                errors.rejectValue("mail1", "lbl_mail1_and_mail2_must_be_equal");
                errors.rejectValue("mail2", "lbl_mail1_and_mail2_must_be_equal");
            }
            if(!user.getPassword1().equals(user.getPassword2())){
                errors.rejectValue("password1", "lbl_pass1_and_pass2_must_be_equal");
                errors.rejectValue("password2", "lbl_pass1_and_pass2_must_be_equal");
            }
        }
最后,注册jsp:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Login</title>
</head>
<body>
    <form:form role="registerModel" commandName="registerModel" method="POST" action="${pageContext.request.contextPath}/zone4/simple/register.htm">
        <form:errors path="*" cssClass="errorblock" element="div" />
        <fieldset>
            <div class="form-group">
                <form:input path="mail1" id="mail1" name="mail1" placeHolder="email" />
                <form:errors path="mail1" id="mail1" name="mail1" placeHolder="email" cssClass="error" />
            </div>
            <div class="form-group">
                <form:input path="mail2" id="mail2" name="mail2" placeHolder="email" />
                <form:errors path="mail2" id="mail2" name="mail2" placeHolder="email" cssClass="error" />
            </div>
            <div class="form-group">
                <form:input path="password1" id="password1" name="password1" placeHolder="password" />
                <form:errors path="password1" id="password1" name="password1" placeHolder="password" cssClass="error" />
            </div>
            <div class="form-group">
                <form:input path="password2" id="password2" name="password2" placeHolder="password" />
                <form:errors path="password2" id="password2" name="password2" placeHolder="password" cssClass="error" />                
            </div>
            <div class="checkbox">
                <label>
                    <input name="remember-me" id="remember-me" type="checkbox" value="Remember Me">Remember Me
                </label>
            </div>
            <!-- Change this to a button or input when using this as a form -->
            <button type="submit" class="btn btn-lg btn-success btn-block" name="submit"><spring:message code="lblRegistration"/></button>
        </fieldset>
    </form:form>
</body>
</html>

最新更新