我有一个spring web应用程序,我使用Spring安全性进行了用户身份验证。
一切都运作良好。登录并退出工作完美!
现在,我想实现以便自动注销。例如,如果用户打开窗口大约30分钟并且什么也不做(例如,会话已过期)系统应该自动注销。我该如何实现呢?
它可能由客户端实现(我每1分钟发送一次请求并检查会话是否结束)。但我不能自动从Spring那里做到这一点吗?
我有这个配置:
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/admin**" />
<access-denied-handler error-page="/403" />
<form-login login-page="/login"
default-target-url="/admin"
authentication-failure-url="/login?error"
username-parameter="NAME"
password-parameter="PASSWORD" />
<logout invalidate-session="true"
logout-success-url="/login?logout"/>
</http>
并在web.xml中
<session-config>
<session-timeout>1</session-timeout>
</session-config>
1分钟后,我看到会话被破坏了。 1分钟后杀死会话。但页面未重定向到/ login?logout
答案 0 :(得分:4)
如何使用安全配置。我希望下面的配置:会工作。
的的applicationContext.xml 强>
--namespace-> xmlns:security="http://www.springframework.org/schema/security"
<security:logout invalidate-session="true"
success-handler-ref="Logout"
logout-url="/logout.html" />
</security:http>
<强>的web.xml 强>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
他们,你需要编写自己的,因为success-handler-ref =“Logout”是注销的自定义处理程序:
<强>注销强>
@Component
public class Logout extends SimpleUrlLogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
if (authentication != null) {
// do something
}
setDefaultTargetUrl("/login");
super.onLogoutSuccess(request, response, authentication);
}
}
答案 1 :(得分:1)
您可以通过将其放在web.xml中来使用全局超时值:
<session-config>
<session-timeout>30</session-timeout>
</session-config>
答案 2 :(得分:0)
这是我使用的教程。有java脚本和服务器端代码。服务器将计算会话何时到期并将其作为cookie发回。然后java脚本将每10秒检查一次是否过期,如果是的话,它将是window.close()。 http://www.javaworld.com/article/2073234/tracking-session-expiration-in-browser.html
以下是我实施它的方式
SessionTimeout.js
/**
* Monitor the session timeout cookie from Apache and log the user out when expired
*/
"use strict";
var jQuery = require("jquery").noConflict();
var jsCookie = require("js-cookie");
module.exports.registerListener = function() {
calcOffset();
checkSession();
};
/**
* We can't assume the server time and client time are the same
* so lets calcuate the difference
*/
function calcOffset() {
var serverTime = jsCookie.get('serverTime');
serverTime = serverTime==null ? null : Math.abs(serverTime);
var clientTimeOffset = (new Date()).getTime() - serverTime;
jsCookie.set('clientTimeOffset', clientTimeOffset);
}
/**
* Check the sessionExpiry cookie and see if we should send the user to /
*/
function checkSession() {
var sessionExpiry = Math.abs(jsCookie.get('sessionExpiry'));
var timeOffset = Math.abs(jsCookie.get('clientTimeOffset'));
var localTime = (new Date()).getTime();
if(!sessionExpiry){
window.console.log("Unknown session sessionExpiry");
return;
}
if (localTime - timeOffset > (sessionExpiry+15000)) { // 15 extra seconds to make sure
window.location = "/login";
jsCookie.remove('sessionExpiry');
} else {
setTimeout('checkSession()', 10000);
}
window.console.log("Session expires in " + ((sessionExpiry+15000) - localTime - timeOffset) + "ms");
}
window.checkSession = checkSession; //Used for recalling via setTimeout
SessionTimeoutCookieFilter.java
public class SessionTimeoutCookieFilter implements Filter {
private static final Logger LOG = LoggerFactory.getLogger(SessionTimeoutCookieFilter.class);
@Override
public void init(FilterConfig config) throws ServletException {
LOG.info("Initialization SessionTimeoutCookieFilter");
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse httpResp = (HttpServletResponse) resp;
HttpServletRequest httpReq = (HttpServletRequest) req;
long currTime = System.currentTimeMillis();
String expiryTime = Long.toString(currTime + httpReq.getSession().getMaxInactiveInterval() * 1000);
Cookie cookie = new Cookie("serverTime", Long.toString(currTime));
cookie.setPath("/");
httpResp.addCookie(cookie);
if (httpReq.getRemoteUser() != null) {
cookie = new Cookie("sessionExpiry", expiryTime);
}
cookie.setPath("/");
httpResp.addCookie(cookie);
filterChain.doFilter(req, resp);
}
添加过滤器
public class ApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
...
@Override
protected Filter[] getServletFilters() {
return new Filter[]{new SessionTimeoutCookieFilter()};
}
}
答案 3 :(得分:0)
要在会话到期后重定向到登录页面,请在安全上下文中将“invalid-session-url”标记添加到“session-management”bean:
<session-management invalid-session-url="/error-login">
....
</session-management>
在我的情况下,我正在重定向到错误登录页面,其中显示错误消息,我可以重新登录。请注意,在会话到期时,您不会被自动重定向。您需要单击页面的任何部分,这将触发重定向。
答案 4 :(得分:0)
可能是spring-security,spring-mvc或servlet,没有完善的客户端逻辑就无法自动注销。
考虑到应用程序将同时具有两种类型的请求
自动注销需要经过精心计算的逻辑。通过以下
展示我的自动注销功能实现
1。如下所示,在所需的JSP页面中包括自动注销脚本。
....
</body>
<jsp:include page="../template/autologout-script.jsp"></jsp:include>
</html>
2。创建一个JSP页面autologout-script.jsp并添加以下代码。 注意:无需编辑/配置
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<script>
$(document).ready(function()
{
var timeOutTimeInSeconds = ${ timeOutTimeInSeconds };
var showTimerTimeInSeconds= ${ showTimerTimeInSeconds };
var sessionCheckIntervalId = setInterval(redirectToLoginPage, timeOutTimeInSeconds * 1000);
var timerDisplayIntervalId = setInterval(showTimer, (timeOutTimeInSeconds - showTimerTimeInSeconds) * 1000);
var badgeTimerId;
window.localStorage.setItem("AjaxRequestFired", new Date());
function redirectToLoginPage(){
//location.href = '<c:url value="/" />'+'${loginPageUrl}';
window.location.reload();
}
$(document).ajaxComplete(function () {
resetTimer();
});
$(window).bind('storage', function (e) {
if(e.originalEvent.key == "AjaxRequestFired"){
console.log("Request sent from another tab, hence resetting timer")
resetTimer();
}
});
function resetTimer()
{
showTimerTimeInSeconds= ${ showTimerTimeInSeconds };
console.log("timeOutTimeInSeconds : "+timeOutTimeInSeconds)
window.localStorage.setItem("AjaxRequestFired", new Date());
window.clearInterval(sessionCheckIntervalId);
sessionCheckIntervalId = setInterval(redirectToLoginPage, timeOutTimeInSeconds * 1000);
window.clearInterval(timerDisplayIntervalId);
timerDisplayIntervalId = setInterval(showTimer, (timeOutTimeInSeconds - showTimerTimeInSeconds) * 1000);
hideTimer();
}
function showTimer()
{
$('#sessionTimeRemaining').show();
$('#sessionTimeRemainingBadge').html(showTimerTimeInSeconds--);
window.clearInterval(timerDisplayIntervalId);
badgeTimerId = setInterval(function(){
$('#sessionTimeRemainingBadge').html(showTimerTimeInSeconds--);
}, 1000);
}
function hideTimer()
{
window.clearInterval(badgeTimerId);
$('#sessionTimeRemaining').hide();
}
});
</script>
3。配置会话属性以配置超时设置 注意:在会话创建后配置此。您可以实现HttpSessionListener sessionCreated方法,并根据需要设置以下配置。
session.setMaxInactiveInterval(300);
session.setAttribute("timeOutTimeInSeconds", 300);
session.setAttribute("showTimerTimeInSeconds", 30);
4。在html下方添加用于显示计时器。
注意:如果您擅长CSS,可以将其移至autologout-script模板页面。因此,您可以避免在每个页面中添加它。
包括引导程序或添加自定义CSS。
<span class="badge badge-primary" title="click to keep session alive" id="sessionTimeRemaining"
onclick="ajaxSessionRefresh()" style="display:none;">
<i class="badge badge-danger" id="sessionTimeRemainingBadge" style="float:left">30</i>
<small>Refresh</small>
<i class="glyphicon glyphicon-refresh"></i>
</span>
这就是简单的自动注销实现。
您可以从我的github存储库下载工作示例
Autologout using simple servlet example
Autologout using spring-security java configuration example
Autologout using spring-security xml configuration example
所需的限制/改进
1.如果最大允许会话数为1,则如果会话是从另一个系统进行的,则AJAX请求将失败。需要处理它以重定向到登录页面。
2.使用ajaxStart()而不是ajaxComplete()在服务器和浏览器之间实现idleTime值的精确同步。
要求
1. jQuery
response.setHeader("Refresh", "60; URL=login.jsp");
<meta http-equiv="refresh" content="60; url=login.jsp">
答案 5 :(得分:0)
我试图使用 JavaScript 和 Spring Boot 为同一问题找出一些合适的解决方案,这对我有用,因为仅使用方法 expiredUrl("/login?expired") 不会将我重定向到带有会话的登录页面过期消息。
HTML 文件:
<body onload="idleLogout();">
</body>
JavaScript:
var t;
function idleLogout() {
window.onload = resetTimer;
window.onmousemove = resetTimer;
window.onmousedown = resetTimer; // catches touchscreen presses
window.onclick = resetTimer; // catches touchpad clicks
window.onscroll = resetTimer; // catches scrolling with arrow keys
window.onkeypress = resetTimer;
function logout() {
window.location = '/login?expired';
}
function resetTimer() {
clearTimeout(t);
t = setTimeout(logout, 1800000); // time is in milliseconds
}
}
30 分钟后,您将被重定向到 /login?expired 并使用以下 HTML 代码:
<div th:style="${param.expired} ? 'width: 100%' : 'width: 0'"
th:text="#{page.login.form.timeout}"
</div>