Как перенаправить на домашнюю страницу, если пользователь обращается к странице входа после входа в систему?
Вот моя конфигурация безопасности 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";
}
Ответы
Ответ 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 означает, что пользователь не аутентифицирован и поэтому может быть отправлен на страницу входа в систему. Я не знаю, насколько это надежное/надежное, но кажется разумным попробовать.