问题
I'm beginner of Spring Framework. Me and my friend are writing our engineer thesis on Poznań University of Technology and we have a problem with Spring Security (3.1.0). I can NOT well log out. When I want to log in again I see message "User is already logged in" (I overrode standard Spring Security error message). I was trying to clear context of SecurityContextHolder but It still doesn't work.
spring-security.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<security:http auto-config="true" create-session="ifRequired">
<security:intercept-url pattern="/start"
access="IS_AUTHENTICATED_ANONYMOUSLY" />
<security:intercept-url pattern="/home" access="ROLE_USER" />
<security:session-management>
<security:concurrency-control
max-sessions="1" error-if-maximum-exceeded="true" />
</security:session-management>
<security:form-login login-page="/start"
default-target-url="/home" authentication-failure-url="/login_error?error=true"
always-use-default-target="true" />
<security:logout invalidate-session="true" logout-success-url="/start" logout-url="/j_spring_security_logout"/>
</security:http>
<security:authentication-manager>
<security:authentication-provider ref="myAuthenticationProvider"/>
</security:authentication-manager>
<bean id="myAuthenticationProvider" name="myAuthenticationProvider" class="org.pp.web.Authentication.XtbAuthenticationProvider"/>
</beans>`
web.xml
<!-- Spring Security -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
home.jsp
<a href="<c:url value="/logout" />">Logout</a>
Controller.java
@RequestMapping(value = "logout")
public String logout() {
SecurityContextHolder.clearContext();
return "redirect:/j_spring_security_logout";
}
@RequestMapping(value = "start")
public String start(Model model, HttpServletRequest request) {
// sprawdzenie czy uzytkownik nie jest juz zalogowany
if (request.getRemoteUser() == null) {
return "start";
} else {
return "redirect:/home";
}
}
I have my own provider to check login and password.
AuthProvider.java
public class AuthenticationProvider implements AuthenticationProvider{
private Logger logger = Logger.getLogger(AuthenticationProvider.class);
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new GrantedAuthorityImpl("ROLE_USER"));
UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication;
String username = String.valueOf(auth.getPrincipal());
String password = String.valueOf(auth.getCredentials());
if(username.length()<4)
{
logger.warn("Error: Login is to short for username: "+ username);
throw new BadCredentialsException("Login is to short!");
}
else if(password.length()<4)
{
logger.warn("Error: Password is to short for username: "+ username);
throw new BadCredentialsException("Password is to short!");
}
else if(!( (username.equals("login") & password.equals("password"))|
(username.equals("login2") & password.equals("password2"))) ) {
logger.warn("Error: Incorrect data for username: "+ username);
throw new BadCredentialsException("Incorrect data!");
}
return new UsernamePasswordAuthenticationToken(
authentication.getName(), authentication.getCredentials(),
authorities);
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
I was trying to fix it and I was looking long time but I can't find solution.
I hope you help me.
Mateusz Jarmuzek, Lukasz Grzybowski
Edit: I overrode standard Spring Security error message.
Code after changes.
Controller.java
@RequestMapping(value = "dummy")
public String dummy() {
//SecurityContextHolder.clearContext();
return "redirect:/dummy";
}
@RequestMapping(value = "logout")
public String logout() {
//SecurityContextHolder.clearContext();
return "redirect:/start";
}
dummy.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<%
session.invalidate();
// String redirectURL = "http://localhost:8080/start";
// response.sendRedirect(redirectURL);
%>
<body>
<%-- <c:redirect url='http://localhost:8080/start' /> --%>
</body>
</html>
home.jsp
<a href="<c:url value='/dummy' />">Logout</a>
回答1:
It's problem no in JSP redirects but in settings.
Try this:
Add to web.xml
<listener>
<listener-class>
org.springframework.security.web.session.HttpSessionEventPublisher
</listener-class>
</listener>
回答2:
The standard for Spring security log outs is as follows:
SecurityContextHolder.clearContext();
EDIT
If you are using jsp redirects, what needs to happen is you need an empty jsp that does the following things:
1) Invalidates the session
2) Redirects to a landing page
When I say empty I mean the only content inside of it is a scriptlet that does the two pieces above. So the process will look as follows:
1) User presses log out
2) A redirect to the dummy page as described above occurs
3) Dummy page executes its code
4) User is now logged out of the system.
JSP CODE
<html>
<%session.invalidate()%>
//redirect logic
</html>
来源:https://stackoverflow.com/questions/13920729/spring-security-cannot-logout