[Spring] إعادة توجيه أمان الربيع إلى الصفحة السابقة بعد تسجيل الدخول بنجاح


Answers

اريد ان امد جواب اولكاى اللطيف مقاربته جيدة ، يجب أن تكون وحدة تحكم صفحة تسجيل الدخول على هذا النحو لوضع عنوان 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 وتجاوز 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);
        }
    }
}

بعد ذلك ، في التكوين الربيعي ، يجب عليك تعريف هذه الفئة المخصصة كحبة واستخدامها على تكوين الأمان. إذا كنت تستخدم تهيئة التعليقات التوضيحية ، فيجب أن تبدو بهذا الشكل (الفئة التي WebSecurityConfigurerAdapter من WebSecurityConfigurerAdapter ):

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

في طريقة configure :

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

أعلم أن هذا السؤال قد طُرح من قبل ، لكني أواجه مشكلة معينة هنا.

أستخدم أمان الربيع 3.1.3.

لدي 3 حالات تسجيل دخول محتملة في تطبيق الويب الخاص بي:

  1. تسجيل الدخول عبر صفحة تسجيل الدخول: OK.
  2. تسجيل الدخول عبر صفحة مقيدة: OK أيضًا.
  3. تسجيل الدخول عبر صفحة غير مقيدة: غير موافق ... يمكن الوصول إلى صفحة "منتج" من قبل الجميع ، ويمكن للمستخدم نشر تعليق إذا كان قد قام بتسجيل الدخول. لذلك يتم تضمين نموذج تسجيل الدخول في نفس الصفحة للسماح للمستخدمين بالاتصال.

المشكلة في الحالة 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>

الحل هنا واضح تمامًا: يُسمح بصفحة تسجيل الدخول فقط للمستخدمين المجهولين. بمجرد اتصال مستخدم ، يعيد معالج الأخطاء توجيهه إلى الصفحة الرئيسية.

لقد أجريت بعض الاختبارات ، ويبدو أن كل شيء يعمل بشكل جيد.




يمكنك استخدام Custom SuccessHandler لتوسيع SimpleUrlAuthenticationSuccessHandler لإعادة توجيه المستخدمين إلى عناوين URL مختلفة عند تسجيل الدخول وفقًا للأدوار المخصصة لهم.

يوفر فئة 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;
    }
}

تمديد Spring SimpleUrlAuthenticationSuccess أسلوب التعامل مع الطبقة والفئة overHiding () الذي يقوم ببساطة باستدعاء عملية إعادة توجيه باستخدام RedirectStrategy مكوّنًا [افتراضي في هذه الحالة] مع عنوان URL الذي تم إعادته بواسطة أسلوب userTargetUrl () المحدد من قبل المستخدم. تقوم هذه الطريقة باستخراج أدوار المستخدم الذي تم تسجيل دخوله حاليًا من كائن المصادقة ثم إنشاء عنوان URL مناسب يستند إلى أدوار. وأخيرًا ، تعمل RedirectStrategy ، المسؤولة عن جميع عمليات إعادة التوجيه ضمن إطار أمان الربيع ، على إعادة توجيه الطلب إلى عنوان URL محدد.

تسجيل CustomSuccessHandler باستخدام فئة SecurityConfiguration:

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 هو الفصل المسؤول عن إعادة التوجيه في نهاية المطاف على أساس أي منطق مخصص ، والذي في هذه الحالة سيتم إعادة توجيه المستخدم [الطالب / المشرف / الموظفين] على أساس دوره [USER / Student / SystemAdmin / UniversityAdmin / ExaminationsStaff / AcademicStaff].




يمكن استخدام الحل العام التالي مع تسجيل الدخول العادي ، أو تسجيل الدخول إلى Spring Social ، أو معظم عوامل تصفية Spring Security الأخرى.

في وحدة التحكم Spring MVC ، عند تحميل صفحة المنتج ، قم بحفظ المسار إلى صفحة المنتج في الجلسة إذا لم يتم تسجيل دخول المستخدم. في XML config ، قم بتعيين عنوان url الافتراضي المستهدف. فمثلا:

في جهاز التحكم في Spring MVC ، يجب أن تقرأ طريقة إعادة التوجيه المسار من الجلسة redirect:<my_saved_product_path> .

لذا ، بعد تسجيل دخول المستخدم ، سيتم إرسالها إلى /redirect الصفحة ، والتي ستعيد توجيهها على الفور إلى صفحة المنتج التي زارها آخر مرة.






Links