(1)踢掉前面的登录
想要用新的登录踢掉旧的登录,我们只需要将最大会话数设置为 1 即可,配置如下:
http.csrf().disable().cors()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.sessionAuthenticationStrategy(new ConcurrentSessionControlAuthenticationStrategy())
.and()
.authorizeRequests()
.antMatchers(resources).permitAll()
.antMatchers(HttpMethod.POST, postMapping).permitAll()
.antMatchers(HttpMethod.GET, getMapping).permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(new Http401AuthenticationEntryPoint())
.and()
.maximumSessions(1)
.sessionRegistry(sessionRegistry)
.maxSessionsPreventsLogin(false);
maximumSessions 表示配置最大会话数为 1,这样后面的登录就会自动踢掉前面的登录
会有以下提示:
This session has been expired (possibly due to multiple concurrent logins being attempted as the same user).
可以看到,这里说这个 session 已经过期,原因则是由于使用同一个用户进行并发登录
(2)解决 session 已经过期的提示
.sessionAuthenticationStrategy(new ConcurrentSessionControlAuthenticationStrategy())
把该类加入到web配置里
public class ConcurrentSessionControlAuthenticationStrategy implements
MessageSourceAware, SessionAuthenticationStrategy {
@Autowired
private SessionRegistry sessionRegistry;
private MessageSource messageSource;
public void onAuthentication(Authentication authentication,
HttpServletRequest request, HttpServletResponse response) {
int sessionCount = 0;
List<SessionInformation> sessions = new ArrayList<>();
if (sessionRegistry!=null) {
sessions = sessionRegistry.getAllSessions(
authentication.getPrincipal(), false);
sessionCount = sessions.size();
int allowedSessions = 1;
if (sessionCount < allowedSessions) {
return;
if (allowedSessions == -1) {
return;
if (sessionCount == allowedSessions) {
HttpSession session = request.getSession(false);
if (session != null) {
for (SessionInformation si : sessions) {
if (si.getSessionId().equals(session.getId())) {
return;
allowableSessionsExceeded(sessions, allowedSessions, sessionRegistry);
protected void allowableSessionsExceeded(List<SessionInformation> sessions,
int allowableSessions, SessionRegistry registry)
throws SessionAuthenticationException {
if ((sessions == null)) {
throw new SessionAuthenticationException(messageSource.getMessage(
"ConcurrentSessionControlAuthenticationStrategy.exceededAllowed",
new Object[] {allowableSessions},
Locale.forLanguageTag("Maximum sessions of {0} for this principal exceeded")));
sessions.sort(Comparator.comparing(SessionInformation::getLastRequest));
int maximumSessionsExceededBy = sessions.size() - allowableSessions + 1;
List<SessionInformation> sessionsToBeExpired = sessions.subList(0, maximumSessionsExceededBy);
for (SessionInformation session: sessionsToBeExpired) {
session.expireNow();
@Override
public void setMessageSource(MessageSource messageSource) {
this.messageSource = messageSource;
一般情况下,用户登录,有两种方式:cookie方式,session方式。一般情况下,session方式是使用最多的。
一、关于session方式原理:
1)浏览器端发起请求,浏览器的cookie中有jsessionId,会随着http 请求,被发送到tomcat服务器端。
2)浏览器端的
登录 token redis key的生成 并限制用户只能登录1个 当登录两个浏览同时访问时会挤掉另外一个 或者可以登录多个账号 这个自己根据自己的需求设计
生成token使用 redis 进行生成 格式为 token+用户id(此id为md5加密 因为不想让用户直接看到自己的id )+生成的token秘钥
实例 “tokenakwdoadwmamd.awdawdawernfiwonefowenfew.ewrfeorjnqwneqweqwe”:“用户基本信息”
当用户登录成功时 拿用户id 进行加密 并且
要实现一个用户不可以同时在两台设备上登录,有两种思路:
(1)后来的登录自动踢掉前面的登录,就像大家在扣扣中看到的效果
(2)如果用户已经登录,则不允许后来者登录。
这种思路都能实现这个功能,具体使用哪一个,还要看我们具体的需求。
在 Spring Security 中,这两种都很好实现,一个配置就可以。
2.具体实现
(1)踢掉前面的登录
想要用新的登录踢掉旧的登录,我们只需要将最大会话数设置为 1 即可,配置如下:
@Override
SpringSecurity中可以使用 SessionRegistry 的实现类 SessionRegistryImpl 来获取session相关信息,可以通过这个实现类来踢出用户。
SpringSecurity配置
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
ISysUserService userService;
@Overri
同一个浏览器上登录多个三员账号,后登陆的会覆盖前面的session,但是前面的页面没有退出(后续请求使用的是后登录的用户的session),导致日志记录等获取的当前操作主体不准确
在 login 方法中加入以下方法
Subject subject = SecurityUtils.getSubject();
if(subject.getPrincipal()!= null){
String msg2=
微服务架构中,不同的服务之间需要进行认证和授权,保证数据和系统的安全性。为此,可以使用springcloud、springboot、oauth2、spring security以及redis等工具来实现微服务的统一认证授权。
首先,利用springboot创建微服务架构,提供微服务的基础框架。然后,使用springcloud来实现微服务的各项功能,包括微服务之间的通讯机制、服务的注册、发现、负载均衡等。
为了保证微服务的安全性,可以采用OAuth2来进行认证和授权。OAuth2最常用的授权模式是资源拥有者密码模式,用户通过在前台输入用户名和密码,获取到访问令牌,通过访问令牌来访问服务。
另外,为了保证安全性,需要使用spring security来进行安全认证,包括通过用户名和密码认证、通过OAuth2认证等方式来保证数据和系统的安全性。
最后,可以使用redis来实现微服务的缓存功能,提升系统的性能和响应速度。通过在微服务架构中集成redis,可以使得不同微服务之间共享数据,提升系统的整体性能。
综上所述,通过springcloud、springboot、oauth2、spring security以及redis等工具来实现微服务的统一认证授权,可以提升微服务架构的安全性和性能,并加强不同微服务之间的协同配合。