mirror of https://github.com/elunez/eladmin
新增在线用户管理,新增注销登录功能,token交于redis管理
parent
e245296c7e
commit
ee33a54f7f
|
@ -1,24 +0,0 @@
|
||||||
package me.zhengjie.modules.monitor.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import java.sql.Timestamp;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Zheng Jie
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class OnlineUser {
|
|
||||||
|
|
||||||
private String userName;
|
|
||||||
|
|
||||||
private String browser;
|
|
||||||
|
|
||||||
private String ip;
|
|
||||||
|
|
||||||
private String address;
|
|
||||||
|
|
||||||
private Date createTime;
|
|
||||||
|
|
||||||
private Date lastAccessTime;
|
|
||||||
}
|
|
|
@ -48,7 +48,7 @@ public class RedisController {
|
||||||
@ApiOperation("清空Redis缓存")
|
@ApiOperation("清空Redis缓存")
|
||||||
@PreAuthorize("hasAnyRole('ADMIN','REDIS_ALL','REDIS_DELETE')")
|
@PreAuthorize("hasAnyRole('ADMIN','REDIS_ALL','REDIS_DELETE')")
|
||||||
public ResponseEntity deleteAll(){
|
public ResponseEntity deleteAll(){
|
||||||
redisService.flushdb();
|
redisService.deleteAll();
|
||||||
return new ResponseEntity(HttpStatus.OK);
|
return new ResponseEntity(HttpStatus.OK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ public interface RedisService {
|
||||||
void delete(String key);
|
void delete(String key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清空所有缓存
|
* 清空缓存
|
||||||
*/
|
*/
|
||||||
void flushdb();
|
void deleteAll();
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,16 +9,17 @@ import org.springframework.data.domain.PageImpl;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Zheng Jie
|
* @author Zheng Jie
|
||||||
* @date 2018-12-10
|
* @date 2018-12-10
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
|
@SuppressWarnings({"unchecked","all"})
|
||||||
public class RedisServiceImpl implements RedisService {
|
public class RedisServiceImpl implements RedisService {
|
||||||
|
|
||||||
private final RedisTemplate redisTemplate;
|
private final RedisTemplate redisTemplate;
|
||||||
|
@ -31,18 +32,18 @@ public class RedisServiceImpl implements RedisService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public Page<RedisVo> findByKey(String key, Pageable pageable){
|
public Page<RedisVo> findByKey(String key, Pageable pageable){
|
||||||
List<RedisVo> redisVos = new ArrayList<>();
|
List<RedisVo> redisVos = new ArrayList<>();
|
||||||
if(!"*".equals(key)){
|
if(!"*".equals(key)){
|
||||||
key = "*" + key + "*";
|
key = "*" + key + "*";
|
||||||
}
|
}
|
||||||
for (Object s : Objects.requireNonNull(redisTemplate.keys(key))) {
|
Set<String> keys = redisTemplate.keys(key);
|
||||||
|
for (String s : keys) {
|
||||||
// 过滤掉权限的缓存
|
// 过滤掉权限的缓存
|
||||||
if (s.toString().contains("role::loadPermissionByUser") || s.toString().contains("user::loadUserByUsername")) {
|
if (s.contains("role::loadPermissionByUser") || s.contains("user::loadUserByUsername") || s.contains("online:token")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
RedisVo redisVo = new RedisVo(s.toString(), Objects.requireNonNull(redisTemplate.opsForValue().get(s.toString())).toString());
|
RedisVo redisVo = new RedisVo(s, Objects.requireNonNull(redisTemplate.opsForValue().get(s)).toString());
|
||||||
redisVos.add(redisVo);
|
redisVos.add(redisVo);
|
||||||
}
|
}
|
||||||
return new PageImpl<RedisVo>(
|
return new PageImpl<RedisVo>(
|
||||||
|
@ -52,14 +53,14 @@ public class RedisServiceImpl implements RedisService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void delete(String key) {
|
public void delete(String key) {
|
||||||
redisTemplate.delete(key);
|
redisTemplate.delete(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void flushdb() {
|
public void deleteAll() {
|
||||||
Objects.requireNonNull(redisTemplate.getConnectionFactory()).getConnection().flushDb();
|
Set<String> keys = redisTemplate.keys( "*");
|
||||||
|
redisTemplate.delete(keys.stream().filter(s -> !s.contains("online:token")).collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -72,7 +73,6 @@ public class RedisServiceImpl implements RedisService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void saveCode(String key, Object val) {
|
public void saveCode(String key, Object val) {
|
||||||
redisTemplate.opsForValue().set(key,val);
|
redisTemplate.opsForValue().set(key,val);
|
||||||
redisTemplate.expire(key,expiration, TimeUnit.MINUTES);
|
redisTemplate.expire(key,expiration, TimeUnit.MINUTES);
|
||||||
|
|
|
@ -89,34 +89,34 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
"/**/*.js"
|
"/**/*.js"
|
||||||
).anonymous()
|
).anonymous()
|
||||||
|
|
||||||
.antMatchers(HttpMethod.POST,"/auth/login").anonymous()
|
.antMatchers(HttpMethod.POST,"/auth/login").permitAll()
|
||||||
.antMatchers(HttpMethod.GET,"/auth/code").anonymous()
|
.antMatchers(HttpMethod.DELETE,"/auth/logout").permitAll()
|
||||||
|
.antMatchers(HttpMethod.GET,"/auth/code").permitAll()
|
||||||
// 支付宝回调
|
// 支付宝回调
|
||||||
.antMatchers("/api/aliPay/return").anonymous()
|
.antMatchers("/api/aliPay/return").permitAll()
|
||||||
.antMatchers("/api/aliPay/notify").anonymous()
|
.antMatchers("/api/aliPay/notify").permitAll()
|
||||||
|
|
||||||
// swagger start
|
// swagger start
|
||||||
.antMatchers("/swagger-ui.html").anonymous()
|
.antMatchers("/swagger-ui.html").permitAll()
|
||||||
.antMatchers("/swagger-resources/**").anonymous()
|
.antMatchers("/swagger-resources/**").permitAll()
|
||||||
.antMatchers("/webjars/**").anonymous()
|
.antMatchers("/webjars/**").permitAll()
|
||||||
.antMatchers("/*/api-docs").anonymous()
|
.antMatchers("/*/api-docs").permitAll()
|
||||||
// swagger end
|
// swagger end
|
||||||
|
|
||||||
// 接口限流测试
|
// 接口限流测试
|
||||||
.antMatchers("/test/**").anonymous()
|
.antMatchers("/test/**").permitAll()
|
||||||
// 文件
|
// 文件
|
||||||
.antMatchers("/avatar/**").anonymous()
|
.antMatchers("/avatar/**").permitAll()
|
||||||
.antMatchers("/file/**").anonymous()
|
.antMatchers("/file/**").permitAll()
|
||||||
|
|
||||||
// 放行OPTIONS请求
|
// 放行OPTIONS请求
|
||||||
.antMatchers(HttpMethod.OPTIONS, "/**").anonymous()
|
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
|
||||||
|
|
||||||
.antMatchers("/druid/**").anonymous()
|
.antMatchers("/druid/**").permitAll()
|
||||||
// 所有请求都需要认证
|
// 所有请求都需要认证
|
||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
// 防止iframe 造成跨域
|
// 防止iframe 造成跨域
|
||||||
.and().headers().frameOptions().disable();
|
.and().headers().frameOptions().disable();
|
||||||
|
|
||||||
httpSecurity
|
httpSecurity
|
||||||
.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
|
.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,17 +12,19 @@ import me.zhengjie.modules.security.security.AuthInfo;
|
||||||
import me.zhengjie.modules.security.security.AuthUser;
|
import me.zhengjie.modules.security.security.AuthUser;
|
||||||
import me.zhengjie.modules.security.security.ImgResult;
|
import me.zhengjie.modules.security.security.ImgResult;
|
||||||
import me.zhengjie.modules.security.security.JwtUser;
|
import me.zhengjie.modules.security.security.JwtUser;
|
||||||
|
import me.zhengjie.modules.security.service.OnlineUserService;
|
||||||
import me.zhengjie.utils.EncryptUtils;
|
import me.zhengjie.utils.EncryptUtils;
|
||||||
import me.zhengjie.modules.security.utils.JwtTokenUtil;
|
import me.zhengjie.modules.security.utils.JwtTokenUtil;
|
||||||
import me.zhengjie.utils.SecurityUtils;
|
import me.zhengjie.utils.SecurityUtils;
|
||||||
import me.zhengjie.utils.StringUtils;
|
import me.zhengjie.utils.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.security.authentication.AccountExpiredException;
|
import org.springframework.security.authentication.AccountExpiredException;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Zheng Jie
|
* @author Zheng Jie
|
||||||
|
@ -35,25 +37,25 @@ import org.springframework.web.bind.annotation.*;
|
||||||
@Api(tags = "系统:系统授权接口")
|
@Api(tags = "系统:系统授权接口")
|
||||||
public class AuthenticationController {
|
public class AuthenticationController {
|
||||||
|
|
||||||
@Value("${jwt.header}")
|
|
||||||
private String tokenHeader;
|
|
||||||
|
|
||||||
private final JwtTokenUtil jwtTokenUtil;
|
private final JwtTokenUtil jwtTokenUtil;
|
||||||
|
|
||||||
private final RedisService redisService;
|
private final RedisService redisService;
|
||||||
|
|
||||||
private final UserDetailsService userDetailsService;
|
private final UserDetailsService userDetailsService;
|
||||||
|
|
||||||
public AuthenticationController(JwtTokenUtil jwtTokenUtil, RedisService redisService, @Qualifier("jwtUserDetailsService") UserDetailsService userDetailsService) {
|
private final OnlineUserService onlineUserService;
|
||||||
|
|
||||||
|
public AuthenticationController(JwtTokenUtil jwtTokenUtil, RedisService redisService, @Qualifier("jwtUserDetailsService") UserDetailsService userDetailsService, OnlineUserService onlineUserService) {
|
||||||
this.jwtTokenUtil = jwtTokenUtil;
|
this.jwtTokenUtil = jwtTokenUtil;
|
||||||
this.redisService = redisService;
|
this.redisService = redisService;
|
||||||
this.userDetailsService = userDetailsService;
|
this.userDetailsService = userDetailsService;
|
||||||
|
this.onlineUserService = onlineUserService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Log("用户登录")
|
@Log("用户登录")
|
||||||
@ApiOperation("登录授权")
|
@ApiOperation("登录授权")
|
||||||
@PostMapping(value = "/login")
|
@PostMapping(value = "/login")
|
||||||
public ResponseEntity login(@Validated @RequestBody AuthUser authorizationUser){
|
public ResponseEntity login(@Validated @RequestBody AuthUser authorizationUser, HttpServletRequest request){
|
||||||
|
|
||||||
// 查询验证码
|
// 查询验证码
|
||||||
String code = redisService.getCodeVal(authorizationUser.getUuid());
|
String code = redisService.getCodeVal(authorizationUser.getUuid());
|
||||||
|
@ -74,10 +76,10 @@ public class AuthenticationController {
|
||||||
if(!jwtUser.isEnabled()){
|
if(!jwtUser.isEnabled()){
|
||||||
throw new AccountExpiredException("账号已停用,请联系管理员");
|
throw new AccountExpiredException("账号已停用,请联系管理员");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成令牌
|
// 生成令牌
|
||||||
final String token = jwtTokenUtil.generateToken(jwtUser);
|
final String token = jwtTokenUtil.generateToken(jwtUser);
|
||||||
|
// 保存在线信息
|
||||||
|
onlineUserService.save(jwtUser, token, request);
|
||||||
// 返回 token
|
// 返回 token
|
||||||
return ResponseEntity.ok(new AuthInfo(token,jwtUser));
|
return ResponseEntity.ok(new AuthInfo(token,jwtUser));
|
||||||
}
|
}
|
||||||
|
@ -102,4 +104,11 @@ public class AuthenticationController {
|
||||||
redisService.saveCode(uuid,result);
|
redisService.saveCode(uuid,result);
|
||||||
return new ImgResult(captcha.toBase64(),uuid);
|
return new ImgResult(captcha.toBase64(),uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiOperation("退出登录")
|
||||||
|
@DeleteMapping(value = "/logout")
|
||||||
|
public ResponseEntity logout(HttpServletRequest request){
|
||||||
|
onlineUserService.logout(jwtTokenUtil.getToken(request));
|
||||||
|
return new ResponseEntity(HttpStatus.OK);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package me.zhengjie.modules.security.rest;
|
||||||
|
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import me.zhengjie.modules.security.service.OnlineUserService;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/auth/online")
|
||||||
|
@Api(tags = "系统:在线用户管理")
|
||||||
|
public class OnlineController {
|
||||||
|
|
||||||
|
private final OnlineUserService onlineUserService;
|
||||||
|
|
||||||
|
public OnlineController(OnlineUserService onlineUserService) {
|
||||||
|
this.onlineUserService = onlineUserService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("查询在线用户")
|
||||||
|
@GetMapping
|
||||||
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
|
public ResponseEntity getAll(String filter, Pageable pageable){
|
||||||
|
return new ResponseEntity<>(onlineUserService.getAll(filter, pageable),HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("踢出用户")
|
||||||
|
@DeleteMapping(value = "/{key}")
|
||||||
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
|
public ResponseEntity delete(@PathVariable String key) throws Exception {
|
||||||
|
onlineUserService.kickOut(key);
|
||||||
|
return new ResponseEntity(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,8 +3,10 @@ package me.zhengjie.modules.security.security;
|
||||||
import io.jsonwebtoken.ExpiredJwtException;
|
import io.jsonwebtoken.ExpiredJwtException;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import me.zhengjie.modules.security.utils.JwtTokenUtil;
|
import me.zhengjie.modules.security.utils.JwtTokenUtil;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
@ -21,38 +23,33 @@ import java.io.IOException;
|
||||||
@Component
|
@Component
|
||||||
public class JwtAuthorizationTokenFilter extends OncePerRequestFilter {
|
public class JwtAuthorizationTokenFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
|
||||||
|
@Value("${jwt.online}")
|
||||||
|
private String onlineKey;
|
||||||
|
|
||||||
private final UserDetailsService userDetailsService;
|
private final UserDetailsService userDetailsService;
|
||||||
private final JwtTokenUtil jwtTokenUtil;
|
private final JwtTokenUtil jwtTokenUtil;
|
||||||
private final String tokenHeader;
|
private final RedisTemplate redisTemplate;
|
||||||
|
|
||||||
public JwtAuthorizationTokenFilter(@Qualifier("jwtUserDetailsService") UserDetailsService userDetailsService, JwtTokenUtil jwtTokenUtil, @Value("${jwt.header}") String tokenHeader) {
|
public JwtAuthorizationTokenFilter(@Qualifier("jwtUserDetailsService") UserDetailsService userDetailsService, JwtTokenUtil jwtTokenUtil, RedisTemplate redisTemplate) {
|
||||||
this.userDetailsService = userDetailsService;
|
this.userDetailsService = userDetailsService;
|
||||||
this.jwtTokenUtil = jwtTokenUtil;
|
this.jwtTokenUtil = jwtTokenUtil;
|
||||||
this.tokenHeader = tokenHeader;
|
this.redisTemplate = redisTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
|
||||||
|
String authToken = jwtTokenUtil.getToken(request);
|
||||||
final String requestHeader = request.getHeader(this.tokenHeader);
|
OnlineUser onlineUser = null;
|
||||||
|
|
||||||
String username = null;
|
|
||||||
String authToken = null;
|
|
||||||
if (requestHeader != null && requestHeader.startsWith("Bearer ")) {
|
|
||||||
authToken = requestHeader.substring(7);
|
|
||||||
try {
|
try {
|
||||||
username = jwtTokenUtil.getUsernameFromToken(authToken);
|
onlineUser = (OnlineUser)redisTemplate.opsForValue().get(onlineKey + authToken);
|
||||||
} catch (ExpiredJwtException e) {
|
} catch (ExpiredJwtException e) {
|
||||||
log.error(e.getMessage());
|
log.error(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
if (onlineUser != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||||
|
|
||||||
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
|
||||||
|
|
||||||
// It is not compelling necessary to load the use details from the database. You could also store the information
|
// It is not compelling necessary to load the use details from the database. You could also store the information
|
||||||
// in the token and read it from it. It's up to you ;)
|
// in the token and read it from it. It's up to you ;)
|
||||||
JwtUser userDetails = (JwtUser)this.userDetailsService.loadUserByUsername(username);
|
JwtUser userDetails = (JwtUser)this.userDetailsService.loadUserByUsername(onlineUser.getUserName());
|
||||||
|
|
||||||
// For simple validation it is completely sufficient to just check the token integrity. You don't have to call
|
// For simple validation it is completely sufficient to just check the token integrity. You don't have to call
|
||||||
// the database compellingly. Again it's up to you ;)
|
// the database compellingly. Again it's up to you ;)
|
||||||
if (jwtTokenUtil.validateToken(authToken, userDetails)) {
|
if (jwtTokenUtil.validateToken(authToken, userDetails)) {
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package me.zhengjie.modules.security.security;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Zheng Jie
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class OnlineUser {
|
||||||
|
|
||||||
|
private String userName;
|
||||||
|
|
||||||
|
private String job;
|
||||||
|
|
||||||
|
private String browser;
|
||||||
|
|
||||||
|
private String ip;
|
||||||
|
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
private String key;
|
||||||
|
|
||||||
|
private Date loginTime;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
package me.zhengjie.modules.security.service;
|
||||||
|
|
||||||
|
import me.zhengjie.modules.security.security.JwtUser;
|
||||||
|
import me.zhengjie.modules.security.security.OnlineUser;
|
||||||
|
import me.zhengjie.utils.EncryptUtils;
|
||||||
|
import me.zhengjie.utils.PageUtil;
|
||||||
|
import me.zhengjie.utils.StringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.PageImpl;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Zheng Jie
|
||||||
|
* @Date 2019年10月26日21:56:27
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@SuppressWarnings({"unchecked","all"})
|
||||||
|
public class OnlineUserService {
|
||||||
|
|
||||||
|
@Value("${jwt.expiration}")
|
||||||
|
private Long expiration;
|
||||||
|
|
||||||
|
@Value("${jwt.online}")
|
||||||
|
private String onlineKey;
|
||||||
|
|
||||||
|
private final RedisTemplate redisTemplate;
|
||||||
|
|
||||||
|
public OnlineUserService(RedisTemplate redisTemplate) {
|
||||||
|
this.redisTemplate = redisTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save(JwtUser jwtUser, String token, HttpServletRequest request){
|
||||||
|
String job = jwtUser.getDept() + "/" + jwtUser.getJob();
|
||||||
|
String ip = StringUtils.getIp(request);
|
||||||
|
String browser = StringUtils.getBrowser(request);
|
||||||
|
String address = StringUtils.getCityInfo(ip);
|
||||||
|
OnlineUser onlineUser = null;
|
||||||
|
try {
|
||||||
|
onlineUser = new OnlineUser(jwtUser.getUsername(), job, browser , ip, address, EncryptUtils.desEncrypt(token), new Date());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
redisTemplate.opsForValue().set(onlineKey + token, onlineUser);
|
||||||
|
redisTemplate.expire(onlineKey + token,expiration, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Page<OnlineUser> getAll(String filter, Pageable pageable){
|
||||||
|
List<String> keys = new ArrayList<>(redisTemplate.keys(onlineKey + "*"));
|
||||||
|
Collections.reverse(keys);
|
||||||
|
List<OnlineUser> onlineUsers = new ArrayList<>();
|
||||||
|
for (String key : keys) {
|
||||||
|
OnlineUser onlineUser = (OnlineUser) redisTemplate.opsForValue().get(key);
|
||||||
|
if(StringUtils.isNotBlank(filter)){
|
||||||
|
if(onlineUser.toString().contains(filter)){
|
||||||
|
onlineUsers.add(onlineUser);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
onlineUsers.add(onlineUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.sort(onlineUsers, (o1, o2) -> {
|
||||||
|
return o2.getLoginTime().compareTo(o1.getLoginTime());
|
||||||
|
});
|
||||||
|
return new PageImpl<OnlineUser>(
|
||||||
|
PageUtil.toPage(pageable.getPageNumber(),pageable.getPageSize(),onlineUsers),
|
||||||
|
pageable,
|
||||||
|
keys.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void kickOut(String val) throws Exception {
|
||||||
|
String key = onlineKey + EncryptUtils.desDecrypt(val);
|
||||||
|
redisTemplate.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void logout(String token) {
|
||||||
|
String key = onlineKey + token;
|
||||||
|
redisTemplate.delete(key);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,8 @@ import me.zhengjie.modules.security.security.JwtUser;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -103,6 +105,14 @@ public class JwtTokenUtil implements Serializable {
|
||||||
.compact();
|
.compact();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getToken(HttpServletRequest request){
|
||||||
|
final String requestHeader = request.getHeader(tokenHeader);
|
||||||
|
if (requestHeader != null && requestHeader.startsWith("Bearer ")) {
|
||||||
|
return requestHeader.substring(7);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public Boolean validateToken(String token, UserDetails userDetails) {
|
public Boolean validateToken(String token, UserDetails userDetails) {
|
||||||
JwtUser user = (JwtUser) userDetails;
|
JwtUser user = (JwtUser) userDetails;
|
||||||
final Date created = getIssuedAtDateFromToken(token);
|
final Date created = getIssuedAtDateFromToken(token);
|
||||||
|
|
|
@ -45,8 +45,10 @@ spring:
|
||||||
jwt:
|
jwt:
|
||||||
header: Authorization
|
header: Authorization
|
||||||
secret: mySecret
|
secret: mySecret
|
||||||
# token 过期时间 6个小时
|
# token 过期时间/毫秒,6小时 1小时 = 3600000 毫秒
|
||||||
expiration: 21000000
|
expiration: 21600000
|
||||||
|
# 在线用户key
|
||||||
|
online: online-token
|
||||||
|
|
||||||
#是否允许生成代码,生产环境设置为false
|
#是否允许生成代码,生产环境设置为false
|
||||||
generator:
|
generator:
|
||||||
|
|
|
@ -49,6 +49,8 @@ jwt:
|
||||||
secret: mySecret
|
secret: mySecret
|
||||||
# token 过期时间 2个小时
|
# token 过期时间 2个小时
|
||||||
expiration: 7200000
|
expiration: 7200000
|
||||||
|
# 在线用户key
|
||||||
|
online: online-token
|
||||||
|
|
||||||
#是否允许生成代码,生产环境设置为false
|
#是否允许生成代码,生产环境设置为false
|
||||||
generator:
|
generator:
|
||||||
|
|
Loading…
Reference in New Issue