成功登录后,Spring Security重定向到上一页

成功登录后,Spring Security重定向到上一页,spring,redirect,login,spring-security,Spring,Redirect,Login,Spring Security,我知道以前有人问过这个问题,但是我在这里面临一个特殊的问题 我使用SpringSecurity 3.1.3 我的web应用程序中有3种可能的登录情况: 通过登录页面登录:OK 通过受限页面登录:也可以 通过非限制页面登录:不确定。。。每个人都可以访问“产品”页面,如果用户已登录,则可以发表评论。因此,登录表单包含在同一页面中,以便允许用户连接 案例3)的问题是我无法将用户重定向到“产品”页面。成功登录后,无论发生什么情况,他们都会被重定向到主页 请注意,对于案例2),成功登录后,重定向到受限页面

我知道以前有人问过这个问题,但是我在这里面临一个特殊的问题

我使用SpringSecurity 3.1.3

我的web应用程序中有3种可能的登录情况:

  • 通过登录页面登录:OK
  • 通过受限页面登录:也可以
  • 通过非限制页面登录:不确定。。。每个人都可以访问“产品”页面,如果用户已登录,则可以发表评论。因此,登录表单包含在同一页面中,以便允许用户连接
  • 案例3)的问题是我无法将用户重定向到“产品”页面。成功登录后,无论发生什么情况,他们都会被重定向到主页

    请注意,对于案例2),成功登录后,重定向到受限页面的操作是现成的

    以下是我的security.xml文件的相关部分:

    <!-- Authentication policy for the restricted page  -->
    <http use-expressions="true" auto-config="true" pattern="/restrictedPage/**">
        <form-login login-page="/login/restrictedLogin" authentication-failure-handler-ref="authenticationFailureHandler" />
        <intercept-url pattern="/**" access="isAuthenticated()" />
    </http>
    
    <!-- Authentication policy for every page -->
    <http use-expressions="true" auto-config="true">
        <form-login login-page="/login" authentication-failure-handler-ref="authenticationFailureHandler" />
        <logout logout-url="/logout" logout-success-url="/" />
    </http>
    
    
    
    我怀疑是“每个页面的身份验证策略”造成了这个问题。但是,如果我删除它,我就不能再登录了。。。j_spring_security_check发送404错误


    编辑:

    多亏拉尔夫,我才找到了解决办法。所以事情是这样的:我用了这个财产

    <property name="useReferer" value="true"/>
    
    
    
    拉尔夫给我看的。在那之后,我的案例1出现了一个问题:当通过登录页面登录时,用户停留在同一页面上(不像以前那样重定向到主页)。在此阶段之前的代码如下:

    <!-- Authentication policy for login page -->
    <http use-expressions="true" auto-config="true" pattern="/login/**">
        <form-login login-page="/login" authentication-success-handler-ref="authenticationSuccessHandlerWithoutReferer" />
    </http>
    
    <!-- Authentication policy for every page -->
    <http use-expressions="true" auto-config="true">
        <form-login login-page="/login" authentication-failure-handler-ref="authenticationFailureHandler" />
        <logout logout-url="/logout" logout-success-url="/" authentication-success-handler-ref="authenticationSuccessHandler"/>
    </http>
    
    <beans:bean id="authenticationSuccessHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
        <!-- After login, return to the last visited page -->
        <beans:property name="useReferer" value="true" />
    </beans:bean>
    
    <beans:bean id="authenticationSuccessHandlerWithoutReferer" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
        <!-- After login, stay to the same page -->
        <beans:property name="useReferer" value="false" />
    </beans:bean>
    
    
    
    至少在理论上,这应该是可行的,但事实并非如此。我仍然不知道为什么,所以如果有人对此有答案,我会很高兴地创建一个新的主题,让他分享他的解决方案

    与此同时,我找到了一个解决办法。这不是最好的解决办法,但就像我说的,如果有人有更好的东西要展示,我会洗耳恭听。因此,这是登录页面的新身份验证策略:

    <http use-expressions="true" auto-config="true" pattern="/login/**" >
        <intercept-url pattern="/**" access="isAnonymous()" />
        <access-denied-handler error-page="/"/>
    </http>
    
    
    
    这里的解决方案非常明显:登录页面只允许匿名用户使用。用户连接后,错误处理程序会将其重定向到主页

    我做了一些测试,一切似乎都很顺利。

    登录后发生的事情(用户重定向到哪个url)由
    AuthenticationSuccessHandler处理

    <bean id="authenticationFilter"
          class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
        <property name="filterProcessesUrl" value="/login/j_spring_security_check" />
        <property name="authenticationManager" ref="authenticationManager" />
        <property name="authenticationSuccessHandler">
            <bean class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
                <property name="useReferer" value="true"/>
            </bean>
        </property>
        <property name="authenticationFailureHandler">
            <bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
                <property name="defaultFailureUrl" value="/login?login_error=t" />
            </bean>
        </property>
    </bean>
    
    此接口(实现它的具体类是
    SavedRequestAwareAuthenticationSuccessHandler
    )由
    AbstractAuthenticationProcessingFilter
    或其子类之一(如
    UsernamePasswordAuthenticationFilter
    )在方法
    successfulAuthentication
    中调用

    因此,为了在案例3中实现另一个重定向,您必须子类化
    SavedRequestAwareAuthenticationSuccessHandler
    ,并使其执行您想要的操作


    有时(取决于您的具体用例),启用
    AbstractAuthenticationTargetUrlRequestHandler
    useReferer
    标志就足够了,该标志由
    SimpleRuthenticationSuccessHandler
    调用(超类
    SavedRequestWareAuthenticationSuccessHandler


    我有以下解决方案,它对我有效

    每当请求登录页面时,将referer值写入会话:

    @RequestMapping(value="/login", method = RequestMethod.GET)
    public String login(ModelMap model,HttpServletRequest request) {
    
        String referrer = request.getHeader("Referer");
        if(referrer!=null){
            request.getSession().setAttribute("url_prior_login", referrer);
        }
        return "user/login";
    }
    
    然后,成功登录后,
    SavedRequestAwareAuthenticationSuccessHandler
    的自定义实现将用户重定向到上一页:

    HttpSession session = request.getSession(false);
    if (session != null) {
        url = (String) request.getSession().getAttribute("url_prior_login");
    }
    
    重定向用户:

    if (url != null) {
        response.sendRedirect(url);
    }
    

    以下通用解决方案可用于常规登录、Spring社交登录或大多数其他Spring安全过滤器

    在Spring MVC控制器中,加载产品页时,如果用户尚未登录,请在会话中保存产品页的路径。在XML配置中,设置默认的目标url。例如:

    在Spring MVC控制器中,重定向方法应该从会话中读取路径并返回
    重定向:


    因此,用户登录后,他们将被发送到
    /redirect
    页面,该页面将立即将他们重定向回上次访问的产品页面。

    我想扩展Olcay的好答案。他的方法很好,您的登录页面控制器应如下所示,将推荐人url放入会话:

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String loginPage(HttpServletRequest request, Model model) {
        String referrer = request.getHeader("Referer");
        request.getSession().setAttribute("url_prior_login", referrer);
        // some other stuff
        return "login";
    }
    
    您应该扩展
    SavedRequestAwareAuthenticationSuccessHandler
    ,并在身份验证成功(HttpServletRequest请求、HttpServletResponse响应、身份验证)时重写其
    方法。大概是这样的:

    public class MyCustomLoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
        public MyCustomLoginSuccessHandler(String defaultTargetUrl) {
            setDefaultTargetUrl(defaultTargetUrl);
        }
    
        @Override
        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
            HttpSession session = request.getSession();
            if (session != null) {
                String redirectUrl = (String) session.getAttribute("url_prior_login");
                if (redirectUrl != null) {
                    // we do not forget to clean this attribute from session
                    session.removeAttribute("url_prior_login");
                    // then we redirect
                    getRedirectStrategy().sendRedirect(request, response, redirectUrl);
                } else {
                    super.onAuthenticationSuccess(request, response, authentication);
                }
            } else {
                super.onAuthenticationSuccess(request, response, authentication);
            }
        }
    }
    
    然后,在spring配置中,应该将这个自定义类定义为bean,并在安全配置中使用它。如果您使用的是注释配置,它应该如下所示(您从
    websecurityConfigureAdapter
    扩展的类):

    配置
    方法中:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // bla bla
                .formLogin()
                    .loginPage("/login")
                    .usernameParameter("username")
                    .passwordParameter("password")
                    .successHandler(successHandler())
                    .permitAll()
                // etc etc
        ;
    }
    

    成功登录后返回上一页,我们可以使用以下自定义身份验证管理器,如下所示:

    <!-- enable use-expressions -->
        <http auto-config="true" use-expressions="true">
            <!-- src** matches: src/bar.c src/baz.c src/test/bartest.c-->
            <intercept-url pattern="/problemSolution/home/**" access="hasRole('ROLE_ADMIN')"/>
            <intercept-url pattern="favicon.ico" access="permitAll"/>
            <form-login
                    authentication-success-handler-ref="authenticationSuccessHandler"
                    always-use-default-target="true"
                    login-processing-url="/checkUser"
                    login-page="/problemSolution/index"
    
                    default-target-url="/problemSolution/home"
                    authentication-failure-url="/problemSolution/index?error"
                    username-parameter="username"
                    password-parameter="password"/>
            <logout logout-url="/problemSolution/logout"
                    logout-success-url="/problemSolution/index?logout"/>
            <!-- enable csrf protection -->
            <csrf/>
        </http>
    
        <beans:bean id="authenticationSuccessHandler"
                class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
            <beans:property name="defaultTargetUrl" value="/problemSolution/home"/>
        </beans:bean>
    
        <!-- Select users and user_roles from database -->
        <authentication-manager>
            <authentication-provider user-service-ref="customUserDetailsService">
                <password-encoder hash="plaintext">
                </password-encoder>
            </authentication-provider>
        </authentication-manager>
    
    
        
            
            
            
            
            
            
            
        
        
            
        
        
        
            
                
                
            
        
    
    CustomUserDetailsService类

    @Service
    public class CustomUserDetailsService implements UserDetailsService {
    
            @Autowired
            private UserService userService;
    
            public UserDetails loadUserByUsername(String userName)
                            throws UsernameNotFoundException {
                    com.codesenior.telif.local.model.User domainUser = userService.getUser(userName);
    
                    boolean enabled = true;
                    boolean accountNonExpired = true;
                    boolean credentialsNonExpired = true;
                    boolean accountNonLocked = true;
    
                    return new User(
                                    domainUser.getUsername(),
                                    domainUser.getPassword(),
                                    enabled,
                                    accountNonExpired,
                                    credentialsNonExpired,
                                    accountNonLocked,
                                    getAuthorities(domainUser.getUserRoleList())
                    );
            }
    
            public Collection<? extends GrantedAuthority> getAuthorities(List<UserRole> userRoleList) {
                    return getGrantedAuthorities(getRoles(userRoleList));
            }
    
            public List<String> getRoles(List<UserRole> userRoleList) {
    
                    List<String> roles = new ArrayList<String>();
    
                    for(UserRole userRole:userRoleList){
                            roles.add(userRole.getRole());
                    }
                    return roles;
            }
    
            public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) {
                    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    
                    for (String role : roles) {
                            authorities.add(new SimpleGrantedAuthority(role));
                    }
                    return authorities;
            }
    
    }
    
    @服务
    公共类CustomUserDetailsService实现UserDetailsService{
    @自动连线
    私人用户服务;
    公共用户详细信息loadUserByUsername(字符串用户名)
    抛出UsernameNotFoundException{
    com.codesior.telif.local.model.User domainUser=userService.getUser(用户名);
    布尔启用=真;
    布尔值accountNonExpired=true;
    布尔凭证非Expired
    
    @Service
    public class CustomUserDetailsService implements UserDetailsService {
    
            @Autowired
            private UserService userService;
    
            public UserDetails loadUserByUsername(String userName)
                            throws UsernameNotFoundException {
                    com.codesenior.telif.local.model.User domainUser = userService.getUser(userName);
    
                    boolean enabled = true;
                    boolean accountNonExpired = true;
                    boolean credentialsNonExpired = true;
                    boolean accountNonLocked = true;
    
                    return new User(
                                    domainUser.getUsername(),
                                    domainUser.getPassword(),
                                    enabled,
                                    accountNonExpired,
                                    credentialsNonExpired,
                                    accountNonLocked,
                                    getAuthorities(domainUser.getUserRoleList())
                    );
            }
    
            public Collection<? extends GrantedAuthority> getAuthorities(List<UserRole> userRoleList) {
                    return getGrantedAuthorities(getRoles(userRoleList));
            }
    
            public List<String> getRoles(List<UserRole> userRoleList) {
    
                    List<String> roles = new ArrayList<String>();
    
                    for(UserRole userRole:userRoleList){
                            roles.add(userRole.getRole());
                    }
                    return roles;
            }
    
            public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) {
                    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    
                    for (String role : roles) {
                            authorities.add(new SimpleGrantedAuthority(role));
                    }
                    return authorities;
            }
    
    }
    
    import com.codesenior.telif.local.model.UserRole;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.userdetails.User;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.stereotype.Service;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.List;
    
    
    @Service
    public class CustomUserDetailsService implements UserDetailsService {
    
            @Autowired
            private UserService userService;
    
            public UserDetails loadUserByUsername(String userName)
                            throws UsernameNotFoundException {
                    com.codesenior.telif.local.model.User domainUser = userService.getUser(userName);
    
                    boolean enabled = true;
                    boolean accountNonExpired = true;
                    boolean credentialsNonExpired = true;
                    boolean accountNonLocked = true;
    
                    return new User(
                                    domainUser.getUsername(),
                                    domainUser.getPassword(),
                                    enabled,
                                    accountNonExpired,
                                    credentialsNonExpired,
                                    accountNonLocked,
                                    getAuthorities(domainUser.getUserRoleList())
                    );
            }
    
            public Collection<? extends GrantedAuthority> getAuthorities(List<UserRole> userRoleList) {
                    return getGrantedAuthorities(getRoles(userRoleList));
            }
    
            public List<String> getRoles(List<UserRole> userRoleList) {
    
                    List<String> roles = new ArrayList<String>();
    
                    for(UserRole userRole:userRoleList){
                            roles.add(userRole.getRole());
                    }
                    return roles;
            }
    
            public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) {
                    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    
                    for (String role : roles) {
                            authorities.add(new SimpleGrantedAuthority(role));
                    }
                    return authorities;
            }
    
    }
    
    @Entity
    public class UserRole {
            @Id
            @GeneratedValue
            private Integer userRoleId;
    
            private String role;
    
            @ManyToMany(fetch = FetchType.LAZY, mappedBy = "userRoleList")
            @JsonIgnore
            private List<User> userList;
    
            public Integer getUserRoleId() {
                    return userRoleId;
            }
    
            public void setUserRoleId(Integer userRoleId) {
                    this.userRoleId= userRoleId;
            }
    
            public String getRole() {
                    return role;
            }
    
            public void setRole(String role) {
                    this.role= role;
            }
    
            @Override
            public String toString() {
                    return String.valueOf(userRoleId);
            }
    
            public List<User> getUserList() {
                    return userList;
            }
    
            public void setUserList(List<User> userList) {
                    this.userList= userList;
            }
    }
    
    package com.mycompany.uomrmsweb.configuration;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.List;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.web.DefaultRedirectStrategy;
    import org.springframework.security.web.RedirectStrategy;
    import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
    import org.springframework.stereotype.Component;
    
    @Component
    public class CustomSuccessHandler extends SimpleUrlAuthenticationSuccessHandler{
    
        private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
    
        @Override
        protected void handle(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
            String targetUrl = determineTargetUrl(authentication);
    
            if (response.isCommitted()) {
                System.out.println("Can't redirect");
                return;
            }
    
            redirectStrategy.sendRedirect(request, response, targetUrl);
        }
    
        protected String determineTargetUrl(Authentication authentication) {
            String url="";
    
            Collection<? extends GrantedAuthority> authorities =  authentication.getAuthorities();
    
            List<String> roles = new ArrayList<String>();
    
            for (GrantedAuthority a : authorities) {
                roles.add(a.getAuthority());
            }
    
            if (isStaff(roles)) {
                url = "/staff";
            } else if (isAdmin(roles)) {
                url = "/admin";
            } else if (isStudent(roles)) {
                url = "/student";
            }else if (isUser(roles)) {
                url = "/home";
            } else {
                url="/Access_Denied";
            }
    
            return url;
        }
    
        public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
            this.redirectStrategy = redirectStrategy;
        }
        protected RedirectStrategy getRedirectStrategy() {
            return redirectStrategy;
        }
    
        private boolean isUser(List<String> roles) {
            if (roles.contains("ROLE_USER")) {
                return true;
            }
            return false;
        }
    
        private boolean isStudent(List<String> roles) {
            if (roles.contains("ROLE_Student")) {
                return true;
            }
            return false;
        }
    
        private boolean isAdmin(List<String> roles) {
            if (roles.contains("ROLE_SystemAdmin") || roles.contains("ROLE_ExaminationsStaff")) {
                return true;
            }
            return false;
        }
    
        private boolean isStaff(List<String> roles) {
            if (roles.contains("ROLE_AcademicStaff") || roles.contains("ROLE_UniversityAdmin")) {
                return true;
            }
            return false;
        }
    }
    
    package com.mycompany.uomrmsweb.configuration;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.core.userdetails.UserDetailsService;
    
    @Configuration
    @EnableWebSecurity
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
        @Autowired
        @Qualifier("customUserDetailsService")
        UserDetailsService userDetailsService;
    
        @Autowired
        CustomSuccessHandler customSuccessHandler;
    
        @Autowired
        public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
                auth.userDetailsService(userDetailsService);
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
            .antMatchers("/", "/home").access("hasRole('USER')")
            .antMatchers("/admin/**").access("hasRole('SystemAdmin') or hasRole('ExaminationsStaff')")
            .antMatchers("/staff/**").access("hasRole('AcademicStaff') or hasRole('UniversityAdmin')")
            .antMatchers("/student/**").access("hasRole('Student')")  
                        .and().formLogin().loginPage("/login").successHandler(customSuccessHandler)
            .usernameParameter("username").passwordParameter("password")
            .and().csrf()
            .and().exceptionHandling().accessDeniedPage("/Access_Denied");
        }
    }
    
    private static class MyCustomLoginSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
    
        private RequestCache requestCache = new HttpSessionRequestCache();
    
        @Override
        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                Authentication authentication) throws ServletException, IOException {
            SavedRequest savedRequest = requestCache.getRequest(request, response);
    
            if (savedRequest == null) {
                HttpSession session = request.getSession();
                if (session != null) {
                    String redirectUrl = (String) session.getAttribute("url_prior_login");
                    if (redirectUrl != null) {
                        session.removeAttribute("url_prior_login");
                        getRedirectStrategy().sendRedirect(request, response, redirectUrl);
                    } else {
                        super.onAuthenticationSuccess(request, response, authentication);
                    }
                } else {
                    super.onAuthenticationSuccess(request, response, authentication);
                }
    
                return;
            }
    
            String targetUrlParameter = getTargetUrlParameter();
            if (isAlwaysUseDefaultTargetUrl()
                    || (targetUrlParameter != null && StringUtils.hasText(request.getParameter(targetUrlParameter)))) {
                requestCache.removeRequest(request, response);
                super.onAuthenticationSuccess(request, response, authentication);
    
                return;
            }
    
            clearAuthenticationAttributes(request);
    
            // Use the DefaultSavedRequest URL
            String targetUrl = savedRequest.getRedirectUrl();
            logger.debug("Redirecting to DefaultSavedRequest Url: " + targetUrl);
            getRedirectStrategy().sendRedirect(request, response, targetUrl);
        }
    }
    
    @RequestMapping(value = "/login", params = "error")
    public String loginError() {
        // Don't save referrer here!
    }
    
    protected void sendStartAuthentication(HttpServletRequest request,...
        ...
        requestCache.saveRequest(request, response);
    
    @Bean
    public RequestCache requestCache() {
       return new HttpSessionRequestCache();
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
       http.authorizeRequests()
       ... 
       .requestCache().requestCache(requestCache()).and()
       ...
    }     
    
    @Autowired
    private RequestCache requestCache;
    
    public void authenticate(HttpServletRequest req, HttpServletResponse resp){
        ....
        SavedRequest savedRequest = requestCache.getRequest(req, resp);
        resp.sendRedirect(savedRequest != null && "GET".equals(savedRequest.getMethod()) ?  
        savedRequest.getRedirectUrl() : "defaultURL");
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        
        
          http.authorizeRequests() 
          .antMatchers("/admin").hasRole("ADMIN") 
          .and()
          .formLogin() .loginPage("/login") 
                        .defaultSuccessUrl("/admin",true)
          .loginProcessingUrl("/authenticateTheUser")
          .permitAll();