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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14573654/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 05:41:03  来源:igfitidea点击:

Spring Security redirect to previous page after successful login

springredirectloginspring-security

提问by Christos Loupassakis

I know this question has been asked before, however I'm facing a particular issue here.

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

I use spring security 3.1.3.

我使用弹簧安全 3.1.3。

I have 3 possible login cases in my web application:

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

  1. Login via the login page : OK.
  2. Login via a restricted page : OK too.
  3. Login via a non-restricted page : not OK... a "product" page can be accessed by everybody, and a user can post a comment if he's logged. So a login form is contained in the same page in order to allow users to connect.
  1. 通过登录页面登录:OK。
  2. 通过受限页面登录:也可以。
  3. 通过不受限制的页面登录:不行……每个人都可以访问“产品”页面,如果用户已登录,则可以发表评论。因此,登录表单包含在同一页面中,以允许用户进行连接。

The problem with case 3) is that I can't manage to redirect users to the "product" page. They get redirected to the home page after a successful login, no matter what.

情况 3) 的问题是我无法将用户重定向到“产品”页面。无论如何,他们都会在成功登录后重定向到主页。

Notice that with case 2) the redirection to the restricted page works out of the box after successful login.

请注意,在情况 2) 中,成功登录后,重定向到受限页面即可开箱即用。

Here's the relevant part of my security.xml file:

这是我的 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>

I suspect the "authentication policy for every page" to be responsible for the problem. However, if I remove it I can't login anymore... j_spring_security_check sends a 404 error.

我怀疑“每个页面的身份验证策略”对问题负责。但是,如果我删除它,我将无法再登录... j_spring_security_check 发送 404 错误。



EDIT:

编辑:

Thanks to Ralph, I was able to find a solution. So here's the thing: I used the property

感谢 Ralph,我找到了解决方案。所以事情是这样的:我使用了财产

<property name="useReferer" value="true"/>

that Ralph showed me. After that I had a problem with my case 1) : when logging via the login page, the user stayed in the same page (and not redirected to the home page, like it used to be). The code until this stage was the following:

拉尔夫给我看的。之后,我的情况 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>

This should work, in theory at least, but it wasn't. I still dont know why, so if someone has an answer on this, I will gladly create a new topic to allo him to share his solution.

至少在理论上,这应该有效,但事实并非如此。我仍然不知道为什么,所以如果有人对此有答案,我很乐意创建一个新主题让他分享他的解决方案。

In the meantime, I came to a workaround. Not the best solution, but like I said, if someone has something better to show, I'm all ears. So this is the new authentication policy for the login page :

与此同时,我找到了一个解决方法。不是最好的解决方案,但就像我说的,如果有人有更好的东西要展示,我全神贯注。所以这是登录页面的新身份验证策略:

<http use-expressions="true" auto-config="true" pattern="/login/**" >
    <intercept-url pattern="/**" access="isAnonymous()" />
    <access-denied-handler error-page="/"/>
</http>

The solution here is pretty obvious: the login page is allowed only for anonymous users. Once a user is connected, the error handler redirects him to the home page.

这里的解决方案非常明显:登录页面只允许匿名用户使用。用户连接后,错误处理程序会将他重定向到主页。

I did some tests, and everything seems to be working nicely.

我做了一些测试,一切似乎都运行良好。

采纳答案by Ralph

What happens after login (to which url the user is redirected) is handled by the AuthenticationSuccessHandler.

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

This interface (a concrete class implementing it is SavedRequestAwareAuthenticationSuccessHandler) is invoked by the AbstractAuthenticationProcessingFilteror one of its subclasses like (UsernamePasswordAuthenticationFilter) in the method successfulAuthentication.

该接口(实现它的具体类SavedRequestAwareAuthenticationSuccessHandler)由方法中的AbstractAuthenticationProcessingFilter或其子类之一(如 ( UsernamePasswordAuthenticationFilter) )调用successfulAuthentication

So in order to have an other redirect in case 3 you have to subclass SavedRequestAwareAuthenticationSuccessHandlerand make it to do what you want.

因此,为了在第 3 种情况下进行其他重定向,您必须子类化SavedRequestAwareAuthenticationSuccessHandler并使其按照您的意愿行事。



Sometimes (depending on your exact usecase) it is enough to enable the useRefererflag of AbstractAuthenticationTargetUrlRequestHandlerwhich is invoked by SimpleUrlAuthenticationSuccessHandler(super class of SavedRequestAwareAuthenticationSuccessHandler).

有时(取决于您的确切用例)足以启用由(的超类)调用的useReferer标志。AbstractAuthenticationTargetUrlRequestHandlerSimpleUrlAuthenticationSuccessHandlerSavedRequestAwareAuthenticationSuccessHandler

<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>

回答by Utku ?zdemir

I want to extend Olcay's nice answer. His approach is good, your login page controller should be like this to put the referrer url into session:

我想扩展Olcay的好答案。他的方法很好,您的登录页面控制器应该像这样将引用网址放入会话:

@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";
}

And you should extend SavedRequestAwareAuthenticationSuccessHandlerand override its onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)method. Something like this:

你应该扩展SavedRequestAwareAuthenticationSuccessHandler和覆盖它的onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)方法。像这样的东西:

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);
        }
    }
}

Then, in your spring configuration, you should define this custom class as a bean and use it on your security configuration. If you are using annotation config, it should look like this (the class you extend from WebSecurityConfigurerAdapter):

然后,在您的 spring 配置中,您应该将此自定义类定义为 bean 并在您的安全配置中使用它。如果您使用annotation config,它应该如下所示(您扩展的类WebSecurityConfigurerAdapter):

@Bean
public AuthenticationSuccessHandler successHandler() {
    return new MyCustomLoginSuccessHandler("/yourdefaultsuccessurl");
}

In configuremethod:

configure方法中:

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

回答by Olcay Tarazan

I have following solution and it worked for me.

我有以下解决方案,它对我有用。

Whenever login page is requested, write the referer value to the session:

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

@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";
}

Then, after successful login custom implementation of SavedRequestAwareAuthenticationSuccessHandlerwill redirect user to the previous page:

然后,成功登录后自定义实现SavedRequestAwareAuthenticationSuccessHandler将用户重定向到上一页:

HttpSession session = request.getSession(false);
if (session != null) {
    url = (String) request.getSession().getAttribute("url_prior_login");
}

Redirect the user:

重定向用户:

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

回答by Grigory Kislin

I've custom OAuth2 authorization and request.getHeader("Referer")is not available at poit of decision. But security request already saved in ExceptionTranslationFilter.handleSpringSecurityException:

我有自定义的 OAuth2 授权,request.getHeader("Referer")在决定时不可用。但是安全请求已经保存在ExceptionTranslationFilter.handleSpringSecurityException

protected void sendStartAuthentication(HttpServletRequest request,...
    ...
    requestCache.saveRequest(request, response);

So, all what we need is share requestCacheas Spring bean:

所以,我们所需要的只是requestCache作为 Spring bean共享:

@Bean
public RequestCache requestCache() {
   return new HttpSessionRequestCache();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
   http.authorizeRequests()
   ... 
   .requestCache().requestCache(requestCache()).and()
   ...
}     

and use it wheen authorization is finished:

并在授权完成后使用它:

@Autowired
private RequestCache requestCache;

public void authenticate(HttpServletRequest req, HttpServletResponse resp){
    ....
    SavedRequest savedRequest = requestCache.getRequest(req, resp);
    resp.sendRedirect(savedRequest == null ? "defaultURL" : savedRequest.getRedirectUrl());
}

回答by Victor Lyuboslavsky

The following generic solution can be used with regular login, a Spring Social login, or most other Spring Security filters.

以下通用解决方案可用于常规登录、Spring Social 登录或大多数其他 Spring Security 过滤器。

In your Spring MVC controller, when loading the product page, save the path to the product page in the session if user has not been logged in. In XML config, set the default target url. For example:

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

In your Spring MVC controller, the redirect method should read out the path from the session and return redirect:<my_saved_product_path>.

在您的 Spring MVC 控制器中,重定向方法应该从会话中读出路径并返回redirect:<my_saved_product_path>.

So, after user logs in, they'll be sent to /redirectpage, which will promptly redirect them back to the product page that they last visited.

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

回答by olyanren

Back to previous page after succesfull login, we can use following custom authentication manager as follows:

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

<!-- 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 class

CustomUserDetailsS​​ervice 类

@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;
????    }

}

User Class

用户类

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;
????    }

}

UserRole Class

用户角色类

@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;
        }
}

回答by Shanika Ediriweera

You can use a Custom SuccessHandler extending SimpleUrlAuthenticationSuccessHandler for redirecting users to different URLs when login according to their assigned roles.

您可以使用自定义 SuccessHandler 扩展 SimpleUrlAuthenticationSuccessHandler 以根据用户分配的角色在登录时将用户重定向到不同的 URL。

CustomSuccessHandler class provides custom redirect functionality:

CustomSuccessHandler 类提供自定义重定向功能:

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;
    }
}

Extending Spring SimpleUrlAuthenticationSuccessHandler class and overriding handle() method which simply invokes a redirect using configured RedirectStrategy [default in this case] with the URL returned by the user defined determineTargetUrl() method. This method extracts the Roles of currently logged in user from Authentication object and then construct appropriate URL based on there roles. Finally RedirectStrategy , which is responsible for all redirections within Spring Security framework , redirects the request to specified URL.

扩展 Spring SimpleUrlAuthenticationSuccessHandler 类并覆盖 handle() 方法,该方法仅使用配置的 RedirectStrategy [在这种情况下为默认值] 和用户定义的确定TargetUrl() 方法返回的 URL 调用重定向。此方法从 Authentication 对象中提取当前登录用户的角色,然后根据这些角色构造适当的 URL。最后,负责 Spring Security 框架内所有重定向的 RedirectStrategy 将请求重定向到指定的 URL。

Registering CustomSuccessHandler using SecurityConfiguration class:

使用 SecurityConfiguration 类注册 CustomSuccessHandler:

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");
    }
}

successHandler is the class responsible for eventual redirection based on any custom logic, which in this case will be to redirect the user [to student/admin/staff ] based on his role [USER/Student/SystemAdmin/UniversityAdmin/ExaminationsStaff/AcademicStaff].

successHandler 是负责根据任何自定义逻辑进行最终重定向的类,在这种情况下,将根据用户的角色 [USER/Student/SystemAdmin/UniversityAdmin/ExaminationsStaff/AcademicStaff] 将用户重定向 [到 student/admin/staff]。

回答by rougou

I found Utku ?zdemir's solutionworks to some extent, but kind of defeats the purpose of the saved request since the session attribute will take precedence over it. This means that redirects to secure pages will not work as intended - after login you will be sent to the page you were on instead of the redirect target. So as an alternative you could use a modified version of SavedRequestAwareAuthenticationSuccessHandler instead of extending it. This will allow you to have better control over when to use the session attribute.

我发现Utku ?zdemir 的解决方案在某种程度上有效,但有点违背了保存请求的目的,因为会话属性将优先于它。这意味着重定向到安全页面将无法按预期工作 - 登录后,您将被发送到您所在的页面而不是重定向目标。因此,作为替代方案,您可以使用 SavedRequestAwareAuthenticationSuccessHandler 的修改版本而不是扩展它。这将使您能够更好地控制何时使用会话属性。

Here is an example:

下面是一个例子:

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);
    }
}

Also, you don't want to save the referrer when authentication has failed, since the referrer will then be the login page itself. So check for the error param manually or provide a separate RequestMapping like below.

此外,您不希望在身份验证失败时保存引用者,因为引用者将成为登录页面本身。因此,请手动检查错误参数或提供如下所示的单独 RequestMapping。

@RequestMapping(value = "/login", params = "error")
public String loginError() {
    // Don't save referrer here!
}