今天有人问如何实现用户不能重复登陆?
我认为是第二个人登录时,第一个用户掉线。
我的思路:
1、当用户登录时,记录下sessionId → key=username,value=session
2、用户再次登录时,检查key是否存在,再次登录是存在的,此时,把session换成再次登录的sessionId,原来的sessionid从httpsession中移除
需要考虑的情况:
1、系统重启
2、不能实现上一个用户登录了,第二个用户不能登录,只能是第二个用户登录使第一个掉线
项目代码:
https://github.com/xcocean/killsession
用到@ServletComponentScan
和@WebListener
注意:Application启动入口需要添加@ServletComponentScan
注解,否则监听失败
实现如下:
1、创建拦截器:
UserInterceptor
@Component // 给spring托管
public class UserInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (request.getSession().getAttribute("username") == null) {
response.sendRedirect("/login");//重定向到登录
return false;
}
return true;
}
}
2、配置拦截器
InterceptorConfig
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
private UserInterceptor userInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//添加拦截器,拦截所有路径
registry.addInterceptor(userInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login");//排除登录的路径
}
}
3、创建session监听
SessionListenerConfig
import com.lingkang.killsession.service.SessionService;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import org.springframework.beans.factory.annotation.Autowired;
/**
* session 监听事件
*/
@WebListener
public class SessionListenerConfig implements HttpSessionListener {
@Autowired
private SessionService sessionService;
/* Session创建事件 */
@Override
public void sessionCreated(HttpSessionEvent event) {
sessionService.create(event.getSession());
}
}
4、创建SessionService
import javax.servlet.http.HttpSession;
public interface SessionService {
void delete(String sessionId);
void create(HttpSession httpSession);
}
实现如下:
SessionServiceImpl
import com.lingkang.killsession.service.SessionService;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Service;
@Service
public class SessionServiceImpl implements SessionService {
//用于存储全部的session,key=sessionid
private Map<String, HttpSession> sessionMap = new HashMap<>();
public void create(HttpSession httpSession) {
sessionMap.put(httpSession.getId(), httpSession);
}
public void delete(String sessionId) {
try {
//移除会话id
sessionMap.get(sessionId).invalidate();
} catch (Exception e) {
}
}
}
5、创建controller
import com.lingkang.killsession.service.SessionService;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
public class UserController {
@Autowired
private HttpServletRequest request;
@Autowired
private SessionService sessionService;
private static Map<String, String> sessionId = new HashMap<>();
@GetMapping(value = {"/", "index"})
public String index() {
return "index";
}
@GetMapping("login")
public String toLogin() {
return "login";
}
@GetMapping("logout")
public String logout(HttpServletResponse response) {
request.getSession().removeAttribute("username");
Cookie[] cookies = request.getCookies();
for (Cookie c : cookies) {
if (c.getName().equals("JSESSIONID")) {
Cookie cookie = new Cookie("JSESSIONID", null);
cookie.setMaxAge(0);
response.addCookie(cookie);
break;
}
}
return "login";
}
@PostMapping("login")
public String login() {
String username = request.getParameter("username");
String password = request.getParameter("password");
if (username.equals("123") && password.equals("123")) {
//登录成功!
//实现只能一个用户登录
//删除上一个session的username
if (sessionId.get(username) != null) {
sessionService.delete(sessionId.get(username));
}
sessionId.put(username, request.getSession().getId());
request.getSession().setAttribute("username", "123");
return "redirect:/index"; //使用重定向,
}
return "login";
}
}
Application中
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@SpringBootApplication
@ServletComponentScan
public class KillsessionApplication {
public static void main(String[] args) {
SpringApplication.run(KillsessionApplication.class, args);
}
}
6、页面:
index.html
<!DOCTYPE html>
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
欢迎您,<b th:text="${session.username}" style="color: red"></b>,您已经登录了<br>
<a href="/logout">注销</a>
</body>
</html>
login.html
<form action="/login" method="post">
账号:<input name="username"><br>
密码<input name="password" type="password"><br><br>
<input value="sign in" type="submit">
</form>