Подтвердить что ты не робот

Как перенаправить на домашнюю страницу, если пользователь обращается к странице входа после входа в систему?

Вот моя конфигурация безопасности spring:

<http pattern="/auth/login" security="none" />
<http pattern="/auth/loginFailed" security="none" />
<http pattern="/resources/**" security="none" />

<http auto-config="true" access-decision-manager-ref="accessDecisionManager">
    <intercept-url pattern="/auth/logout" access="permitAll"/>
    <intercept-url pattern="/admin/**" access="ADMINISTRATIVE_ACCESS"/>
    <intercept-url pattern="/**" access="XYZ_ACCESS"/>

    <form-login
        login-page="/auth/login"
        authentication-failure-url="/auth/loginFailed"
        authentication-success-handler-ref="authenticationSuccessHandler" />
    <logout logout-url="/auth/logout" logout-success-url="/auth/login" />
</http>

authenticationSuccessHandler расширяет SavedRequestAwareAuthenticationSuccessHandler, гарантируя, что пользователь перенаправляется на запрашиваемую им страницу.

Однако, поскольку /auth/login помечен как security="none", я не могу успешно перенаправить пользователя на домашнюю страницу, если он обратился к странице входа в систему после входа в систему. Я считаю, что это правильный .

Я тоже попробовал это, но объект Principal всегда null, предположительно из-за атрибута security="none".

@RequestMapping(value = "/auth/login", method = GET)
public String showLoginForm(HttpServletRequest request, Principal principal) {
    if(principal != null) {
        return "redirect:/";
    }

    return "login";
}
4b9b3361

Ответ 1

Я проверил тему более глубоко, чем в прошлый раз, и обнаружил, что вам нужно определить, аутентифицирован ли пользователь самостоятельно в контроллере. Row Winch (Spring Security dev) говорит здесь:

Spring Безопасность не знает о внутренних компонентах вашего приложения (т.е. если вы хотите, чтобы ваша страница логина входа основывалась на том, если пользователь входит в систему или нет). Чтобы показать свою домашнюю страницу, когда страница входа в систему и пользователь вошел в систему с помощью SecurityContextHolder в страницу входа (или ее контроллера) и перенаправить или перенаправить пользователя на на главной странице.

Таким образом, решение будет определять, является ли пользователь, запрашивающий /auth/login анонимным или нет, что-то вроде ниже.

ApplicationContext-security.xml:

<http auto-config="true" use-expressions="true"
        access-decision-manager-ref="accessDecisionManager">
    <intercept-url pattern="/auth/login" access="permitAll" />
    <intercept-url pattern="/auth/logout" access="permitAll" />
    <intercept-url pattern="/admin/**" access="ADMINISTRATIVE_ACCESS" />
    <intercept-url pattern="/**" access="XYZ_ACCESS" />

    <form-login login-page="/auth/login"
        authentication-failure-url="/auth/loginFailed"
        authentication-success-handler-ref="authenticationSuccessHandler" />
    <logout logout-url="/auth/logout" logout-success-url="/auth/login" />
</http>

<beans:bean id="defaultTargetUrl" class="java.lang.String">
    <beans:constructor-arg value="/content" />
</beans:bean>

<beans:bean id="authenticationTrustResolver"
        class="org.springframework.security.authentication.AuthenticationTrustResolverImpl" />

<beans:bean id="authenticationSuccessHandler"
        class="com.example.spring.security.MyAuthenticationSuccessHandler">
    <beans:property name="defaultTargetUrl" ref="defaultTargetUrl" />
</beans:bean>

Добавить в applicationContext.xml bean определение:

<bean id="securityContextAccessor"
    class="com.example.spring.security.SecurityContextAccessorImpl" />

который является классом

public final class SecurityContextAccessorImpl
      implements SecurityContextAccessor {

  @Autowired
  private AuthenticationTrustResolver authenticationTrustResolver;

  @Override
  public boolean isCurrentAuthenticationAnonymous() {
    final Authentication authentication =
        SecurityContextHolder.getContext().getAuthentication();
    return authenticationTrustResolver.isAnonymous(authentication);
  }
}

реализация простого интерфейса

public interface SecurityContextAccessor {
  boolean isCurrentAuthenticationAnonymous();
}

(SecurityContextHolder доступ к коду развязан с контроллера, я следил за предложением из этого ответа, следовательно SecurityContextAccessor.)

И последнее, но не менее важное: перенаправить логику в контроллер:

@Controller
@RequestMapping("/auth")
public class AuthController {
  @Autowired
  SecurityContextAccessor securityContextAccessor;

  @Autowired
  @Qualifier("defaultTargetUrl")
  private String defaultTargetUrl;

  @RequestMapping(value = "/login", method = RequestMethod.GET)
  public String login() {
    if (securityContextAccessor.isCurrentAuthenticationAnonymous()) {
      return "login";
    } else {
      return "redirect:" + defaultTargetUrl;
    }
  }
}

Определение defaultTargetUrl String bean кажется взломанным, но у меня нет лучшего способа не указывать url... (На самом деле в нашем проекте мы используем <util:constant> с классом, содержащим статические конечные строковые поля.) Но он работает в конце концов.

Ответ 2

Вы также можете ограничить свою страницу входа ROLE_ANONYMOUS и установить <access-denied-handler />:

<access-denied-handler ref="accessDeniedHandler" />
<intercept-url pattern="/auth/login" access="ROLE_ANONYMOUS" />

И в вашем обработчике проверьте, уже ли пользователь аутентифицирован:

@Service
public class AccessDeniedHandler extends AccessDeniedHandlerImpl {
    private final String HOME_PAGE = "/index.html";

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null && !(auth instanceof AnonymousAuthenticationToken)) {
            response.sendRedirect(HOME_PAGE);
        }

        super.handle(request, response, e);
    }
}

Ответ 3

Внедрите перехватчик переадресации для этой цели:

Перехватчик (реализующий HandlerInterceptor интерфейс) проверьте, кто-то пытается получить доступ к странице входа в систему, и если этот человек уже вошел в систему, то перехватчик отправляет перенаправление на индексную страницу.

public class LoginPageRedirectInterceptor extends HandlerInterceptorAdapter {    

    private String[] loginPagePrefixes = new String[] { "/login" };

    private String redirectUrl = "/index.html";

    private UrlPathHelper urlPathHelper = new UrlPathHelper();

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {

        if (isInLoginPaths(this.urlPathHelper.getLookupPathForRequest(request))
                           && isAuthenticated()) {
            response.setContentType("text/plain");
            sendRedirect(request, response);
            return false;
        } else {
            return true;
        }
    }

    private boolean isAuthenticated() {
        Authentication authentication =
                        SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null) {
            return false;
        }
        if (authentication instanceof AnonymousAuthenticationToken) {
            return false;
        }
        return authentication.isAuthenticated();
    }

    private void sendRedirect(HttpServletRequest request,
                              HttpServletResponse response) {

        String encodedRedirectURL = response.encodeRedirectURL(
                                 request.getContextPath() + this.redirectUrl);
        response.setStatus(HttpStatus.SC_TEMPORARY_REDIRECT);
        response.setHeader("Location", encodedRedirectURL);
    }

    private boolean isInLoginPaths(final String requestUrl) {   
        for (String login : this.loginPagePrefixes) {
            if (requestUrl.startsWith(login)) {
                return true;
            }
        }
        return false;
    }
}

Ответ 4

Вы можете сохранить его простым потоком атрибутом access-denied-page в элементе http или как dtrunk, чтобы написать обработчик для отказа в доступе, а также. config будет выглядеть как

<http access-denied-page="/403" ... >
 <intercept-url pattern="/login" access="ROLE_ANONYMOUS" />
 <intercept-url pattern="/user/**" access="ROLE_USER" />
 <intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
 <form-login login-page="/login" default-target-url="/home" ... />
 ...
</http>

в контроллере для /403

@RequestMapping(value = "/403", method = RequestMethod.GET)
public String accessDenied() { //simple impl
    return "redirect:/home";
}

и для /home

@RequestMapping(value = "/home", method = RequestMethod.GET)
public String home(Authentication authentication) {
 // map as many home urls with Role
    Map<String, String> dashBoardUrls = new HashMap<String, String>();
    dashBoardUrls.put("ROLE_USER", "/user/dashboard");
    dashBoardUrls.put("ROLE_ADMIN", "/admin/dashboard");

    String url = null;

    Collection<? extends GrantedAuthority> grants = authentication
            .getAuthorities();
 // for one role per user
    for (GrantedAuthority grantedAuthority : grants) {
        url = dashBoardUrls.get(grantedAuthority.getAuthority());
    }
    if (url == null)
        return "/errors/default_access_denied.jsp";

    return "redirect:" + url;
}

и когда вы выполните запрос /admin/dashboard без входа в систему, он автоматически перенаправит /login с помощью безопасности

Ответ 5

<http pattern="/login" auto-config="true" disable-url-rewriting="true">
  <intercept-url pattern="/login" access="ROLE_ANONYMOUS"/>
  <access-denied-handler error-page="/index.jsp"/>
</http>

Ответ 6

Вы можете попробовать проверить

if(SecurityContextHolder.getContext().getAuthentication() == null)

True означает, что пользователь не аутентифицирован и поэтому может быть отправлен на страницу входа в систему. Я не знаю, насколько это надежное/надежное, но кажется разумным попробовать.