【问题标题】:Spring security: New user workflowSpring security:新的用户工作流程
【发布时间】:2017-01-19 12:07:40
【问题描述】:

我是 Spring 安全的新手。

我创建了一个自定义表单,用于登录用户,然后在成功登录后,用户继续访问他/她的预期网页。我的实现是标准的,并且有效。

这是我的问题。

  • 用户想要访问页面 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;
}

【问题讨论】:

    标签: spring spring-mvc spring-security


    【解决方案1】:

    您可以使用SavedRequestAwareAuthenticationSuccessHandler

    当一个非授权请求到达ExceptionTranslationFilter时,会创建一个HttpSessionRequestCache类的RequestCache,并将原始请求保存在上面。

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

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

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

    安全性.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  
    
    }
    

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

    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>
    

    【讨论】:

    • 真的很有帮助。我将在今天,明天继续工作,并在验证后投票。只是想让您知道我已阅读并感谢您的意见
    猜你喜欢
    • 2011-12-12
    • 2015-11-27
    • 2015-12-15
    • 2014-05-10
    • 2020-04-10
    • 2011-04-25
    • 2015-12-20
    • 2018-07-13
    • 2017-04-14
    相关资源
    最近更新 更多