[SPRING] Spring Security는 로그인 성공 후 이전 페이지로 리다이렉트한다.
SPRINGSpring Security는 로그인 성공 후 이전 페이지로 리다이렉트한다.
나는이 질문이 이전에 질문 받았다는 것을 알고 있지만, 나는 여기서 특별한 문제에 직면하고있다.
나는 스프링 보안 3.1.3을 사용한다.
내 웹 응용 프로그램에 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 오류를 보냅니다.
편집하다:
Ralph 덕분에 솔루션을 찾을 수있었습니다. 그래서 여기에 그 물건이 있습니다 : 나는 그 재산을 사용했다.
<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>
여기의 해결책은 매우 분명합니다. 로그인 페이지는 익명 사용자에게만 허용됩니다. 사용자가 연결되면 오류 처리기가 그를 홈 페이지로 리디렉션합니다.
몇 가지 테스트를했는데 모든 것이 잘 작동하는 것처럼 보입니다.
해결법
-
==============================
1.로그인 후 (사용자가 리디렉션되는 url) AuthenticationSuccessHandler가 처리합니다.
로그인 후 (사용자가 리디렉션되는 url) AuthenticationSuccessHandler가 처리합니다.
이 인터페이스 (그것을 구현하는 구체적인 클래스는 SavedRequestAwareAuthenticationSuccessHandler 임)는 AbstractAuthenticationProcessingFilter 또는 successAuthentication 메소드의 (UsernamePasswordAuthenticationFilter)와 같은 하위 클래스 중 하나에 의해 호출됩니다.
따라서 3 번 사례에서 다른 리디렉션을 사용하려면 SavedRequestAwareAuthenticationSuccessHandler의 하위 클래스를 만들고 원하는 작업을 수행해야합니다.
SimpleUrlAuthenticationSuccessHandler (수퍼 클래스 인 SavedRequestAwareAuthenticationSuccessHandler)에 의해 호출되는 AbstractAuthenticationTargetUrlRequestHandler의 useReferer 플래그를 활성화하는 것으로 충분할 때도 있습니다 (정확한 용도에 따라 다름).
<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>
-
==============================
2.올레이의 멋진 대답을 연장하고 싶습니다. 그의 접근 방식은 좋지만 로그인 페이지 컨트롤러는 다음과 같이 리퍼러 URL을 세션에 넣어야합니다.
올레이의 멋진 대답을 연장하고 싶습니다. 그의 접근 방식은 좋지만 로그인 페이지 컨트롤러는 다음과 같이 리퍼러 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 요청, 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); } } }
그런 다음 봄 구성에서이 사용자 정의 클래스를 bean으로 정의하고 보안 구성에서 사용해야합니다. 주석 설정을 사용하는 경우 WebSecurityConfigurerAdapter에서 확장 한 클래스처럼 보일 것입니다.
@Bean public AuthenticationSuccessHandler successHandler() { return new MyCustomLoginSuccessHandler("/yourdefaultsuccessurl"); }
구성 방법 :
@Override protected void configure(HttpSecurity http) throws Exception { http // bla bla .formLogin() .loginPage("/login") .usernameParameter("username") .passwordParameter("password") .successHandler(successHandler()) .permitAll() // etc etc ; }
-
==============================
3.나는 다음과 같은 해결책을 가지고 있으며 나를 위해 일했다.
나는 다음과 같은 해결책을 가지고 있으며 나를 위해 일했다.
로그인 페이지가 요청 될 때마다 세션에 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); }
-
==============================
4.다음 일반 솔루션은 일반 로그인, Spring Social 로그인 또는 대부분의 다른 스프링 보안 필터와 함께 사용할 수 있습니다.
다음 일반 솔루션은 일반 로그인, Spring Social 로그인 또는 대부분의 다른 스프링 보안 필터와 함께 사용할 수 있습니다.
Spring MVC 컨트롤러에서 제품 페이지를로드 할 때 사용자가 로그인하지 않았다면 세션의 제품 페이지 경로를 저장한다. XML 설정에서 기본 대상 URL을 설정한다. 예 :
Spring MVC 컨트롤러에서 redirect 메소드는 세션에서 경로를 읽고 return redirect :
를 리턴해야한다. 따라서 사용자가 로그인하면 / 리디렉션 페이지로 전송되어 즉시 방문한 제품 페이지로 다시 리디렉션됩니다.
-
==============================
5.로그인 성공 후 이전 페이지로 돌아 가면 다음과 같이 다음과 같은 사용자 정의 인증 관리자를 사용할 수 있습니다.
로그인 성공 후 이전 페이지로 돌아 가면 다음과 같이 다음과 같은 사용자 정의 인증 관리자를 사용할 수 있습니다.
<!-- 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; } }
사용자 등급
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 클래스
@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; } }
-
==============================
6.할당 된 역할에 따라 로그인 할 때 사용자를 다른 URL로 리디렉션하기 위해 SimpleUrlAuthenticationSuccessHandler를 확장하는 Custom SuccessHandler를 사용할 수 있습니다.
할당 된 역할에 따라 로그인 할 때 사용자를 다른 URL로 리디렉션하기 위해 SimpleUrlAuthenticationSuccessHandler를 확장하는 Custom SuccessHandler를 사용할 수 있습니다.
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 SimpleUrlAuthenticationSuccessHandler 클래스를 확장하고 사용자 정의 된 determineTargetUrl () 메소드에 의해 반환 된 URL로 구성된 RedirectStrategy [이 경우에는 기본값]를 사용하여 간단히 리디렉션을 호출하는 handle () 메소드를 재정의합니다. 이 메소드는 현재 로그인 한 사용자의 역할을 인증 객체에서 추출한 다음 역할에 따라 적절한 URL을 구성합니다. 마지막으로 Spring Security 프레임 워크 내의 모든 리다이렉션을 담당하는 RedirectStrategy는 요청을 지정된 URL로 리디렉션합니다.
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는 사용자 지정 논리를 기반으로 최종 리디렉션을 담당하는 클래스입니다.이 경우 사용자 역할 ([USER / Student / SystemAdmin / UniversityAdmin / ExaminationsStaff / AcademicStaff])을 기반으로 사용자를 [student / admin / staff]로 리디렉션합니다.
-
==============================
7.Utku Özdemir의 솔루션은 어느 정도는 작동하지만 세션 속성이 우선하기 때문에 저장된 요청의 목적에 위배됩니다. 즉, 보안 페이지로의 리디렉션은 의도 한대로 작동하지 않습니다. 로그인하면 리디렉션 대상 대신 사용했던 페이지로 전송됩니다. 그래서 대안으로 확장 된 대신 SavedRequestAwareAuthenticationSuccessHandler의 수정 된 버전을 사용할 수 있습니다. 이렇게하면 세션 속성을 사용할시기를 효과적으로 제어 할 수 있습니다.
Utku Özdemir의 솔루션은 어느 정도는 작동하지만 세션 속성이 우선하기 때문에 저장된 요청의 목적에 위배됩니다. 즉, 보안 페이지로의 리디렉션은 의도 한대로 작동하지 않습니다. 로그인하면 리디렉션 대상 대신 사용했던 페이지로 전송됩니다. 그래서 대안으로 확장 된 대신 SavedRequestAwareAuthenticationSuccessHandler의 수정 된 버전을 사용할 수 있습니다. 이렇게하면 세션 속성을 사용할시기를 효과적으로 제어 할 수 있습니다.
다음은 그 예입니다.
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을 제공하십시오.
@RequestMapping(value = "/login", params = "error") public String loginError() { // Don't save referrer here! }
from https://stackoverflow.com/questions/14573654/spring-security-redirect-to-previous-page-after-successful-login by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] http가 상태가 없다고 할 때의 의미는 무엇입니까? (0) | 2018.12.06 |
---|---|
[SPRING] Spring RestTemplate 요청에 "Accept :"헤더를 설정하는 방법? (0) | 2018.12.06 |
[SPRING] 독립 실행 형 Java 응용 프로그램에서 Spring 3 자동 배선 사용 (0) | 2018.12.06 |
[SPRING] util 스키마를 사용하여리스트를 자동 배선하는 것은 NoSuchBeanDefinitionException을 준다. (0) | 2018.12.06 |
[SPRING] 고정 값으로 JPA의 enum을 매핑 하시겠습니까? (0) | 2018.12.06 |