最近,说有可能要上只允许一个地方登录,还要配合信息推送,今天有空,就起个头,把登录超时、登录踢人下线一起做了。信息推送的,后面再说,留好口子就行。
这里是spring security,其实这块已经很成熟了,加几个配置就行。
/**
* 安全认证配置
*
* @author zhengwen
*/
@Configuration
@EnableWebSecurity
@Order(1)
public class LinkappSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Resource
private SessionInformationExpiredStrategy sessionInformationExpiredStrategy;
@Resource
private InvalidSessionStrategy invalidSessionStrategy;
@Override
protected void configure(HttpSecurity http) throws Exception {
// 解决 spring security 对于开放接口返回乱码的解决
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
filter.setForceEncoding(true);
http.addFilterBefore(filter, CsrfFilter.class);
http.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
http
// 禁止匿名用户
// .anonymous().disable()
// 禁止csrfz
.csrf().disable()
// 认证失败处理
.exceptionHandling()
.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
.and()
// 白名单
.authorizeRequests()
.antMatchers("/swagger-ui.html", "/webjars/**", "/swagger-resources/**", "/v2/api-docs/**", "/enterpriseEditionBi/**","/oss/download/**","/download/**","/config/getEduUrl")
.permitAll()
// 接口调试阶段 目前不校验接口 modify by tongjie
.anyRequest().authenticated().and()
// 表单登录配置
.formLogin()
// 登录成功处理
.successHandler(linkappRestAuthenticationSuccessHandler)
// 登录失败处理
.failureHandler(linkappRestAuthenticationFailureHandler).and()
// 登出成功处理
.logout().logoutSuccessHandler(linkappRestLogoutSuccessHandler);
//一个账号只允许一个地方登录,
http.sessionManagement()
//session失效,调用此方法
.invalidSessionStrategy(invalidSessionStrategy).maximumSessions(1)
// 当用户达到最大session数后,则调用此处的实现
.expiredSessionStrategy(sessionInformationExpiredStrategy);
}
@Bean
@ConditionalOnMissingBean(InvalidSessionStrategy.class)
public InvalidSessionStrategy invalidSessionStrategy() {
return new MyInvalidSessionStrategy();
}
@Bean
@ConditionalOnMissingBean(SessionInformationExpiredStrategy.class)
public SessionInformationExpiredStrategy informationExpiredStrategy() {
return new MySessionInformationExpiredStrategy();
}
}
http.sessionManagement()开始就是本次分享内容。注意下面的2个bean,@Bean注解的。
/**
* @author zhengwen
*/
public class MyInvalidSessionStrategy implements InvalidSessionStrategy {
@Override
public void onInvalidSessionDetected(HttpServletRequest httpServletRequest, HttpServletResponse response) throws IOException {
/* 接口请求没有页面,给统一的友好提示,可以直接利用封装的的业务异常
response.setStatus(HttpStatus.HTTP_UNAUTHORIZED);
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("当前登录已失效!请重新登录");
*/
throw new BusinessException("当前登录已失效!请重新登录");
}
}
BusinessException是封装的业务异常类。
/**
* @author zhengwen
*/
@Slf4j
@Component
public class MySessionInformationExpiredStrategy implements SessionInformationExpiredStrategy {
@Autowired
private LinkappRestAuthenticationFailureHandler myAuthenticationFailureHandler;
@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) {
// 1. 获取用户名
UserDetails userDetails =
(UserDetails) event.getSessionInformation().getPrincipal();
AuthenticationException exception =
new AuthenticationServiceException(
String.format("[%s]用户在其他地方登录,您已被下线", userDetails.getUsername()));
//TODO 这里可以增加根据用户名找到手机号信息,进行推送信息,或者在myAuthenticationFailureHandler里去处理
try {
// 当用户在另外终端登录后,交给失败处理器回到认证页面
event.getRequest().setAttribute("toAuthentication", true);
myAuthenticationFailureHandler
.onAuthenticationFailure(event.getRequest(), event.getResponse(), exception);
} catch (Exception e) {
log.error("--登录失效session清除异常,原因:{}", e.getMessage());
throw new BusinessException("超时登录session清除异常");
}
}
}
/**
* 认证失败处理者
*
* @author zhengwen
*/
@Component
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) {
//TODO 自己的异常处理逻辑
RestMessage message = RestBuilders.failureBuilder().code("login.failure")
.message(exception.getMessage()).build();
Responses.standard(response).respond(message);
}
}




多的废话以不想说了额,这一组图看的真真的。