mirror of https://github.com/elunez/eladmin
				
				
				
			新增在线用户管理,新增注销登录功能,token交于redis管理
							parent
							
								
									e245296c7e
								
							
						
					
					
						commit
						ee33a54f7f
					
				| 
						 | 
				
			
			@ -37,8 +37,8 @@ public class GeneratorController {
 | 
			
		|||
    @ApiOperation("查询数据库元数据")
 | 
			
		||||
    @GetMapping(value = "/tables")
 | 
			
		||||
    public ResponseEntity getTables(@RequestParam(defaultValue = "") String name,
 | 
			
		||||
                                   @RequestParam(defaultValue = "0")Integer page,
 | 
			
		||||
                                   @RequestParam(defaultValue = "10")Integer size){
 | 
			
		||||
                                    @RequestParam(defaultValue = "0")Integer page,
 | 
			
		||||
                                    @RequestParam(defaultValue = "10")Integer size){
 | 
			
		||||
        int[] startEnd = PageUtil.transToStartEnd(page+1, size);
 | 
			
		||||
        return new ResponseEntity<>(generatorService.getTables(name,startEnd), HttpStatus.OK);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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缓存")
 | 
			
		||||
    @PreAuthorize("hasAnyRole('ADMIN','REDIS_ALL','REDIS_DELETE')")
 | 
			
		||||
    public ResponseEntity deleteAll(){
 | 
			
		||||
        redisService.flushdb();
 | 
			
		||||
        redisService.deleteAll();
 | 
			
		||||
        return new ResponseEntity(HttpStatus.OK);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,7 +38,7 @@ public interface RedisService {
 | 
			
		|||
    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.redis.core.RedisTemplate;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Zheng Jie
 | 
			
		||||
 * @date 2018-12-10
 | 
			
		||||
 */
 | 
			
		||||
@Service
 | 
			
		||||
@SuppressWarnings({"unchecked","all"})
 | 
			
		||||
public class RedisServiceImpl implements RedisService {
 | 
			
		||||
 | 
			
		||||
    private final RedisTemplate redisTemplate;
 | 
			
		||||
| 
						 | 
				
			
			@ -31,18 +32,18 @@ public class RedisServiceImpl implements RedisService {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @SuppressWarnings("unchecked")
 | 
			
		||||
    public Page<RedisVo> findByKey(String key, Pageable pageable){
 | 
			
		||||
        List<RedisVo> redisVos = new ArrayList<>();
 | 
			
		||||
        if(!"*".equals(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;
 | 
			
		||||
            }
 | 
			
		||||
            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);
 | 
			
		||||
        }
 | 
			
		||||
        return new PageImpl<RedisVo>(
 | 
			
		||||
| 
						 | 
				
			
			@ -52,14 +53,14 @@ public class RedisServiceImpl implements RedisService {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @SuppressWarnings("unchecked")
 | 
			
		||||
    public void delete(String key) {
 | 
			
		||||
        redisTemplate.delete(key);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void flushdb() {
 | 
			
		||||
        Objects.requireNonNull(redisTemplate.getConnectionFactory()).getConnection().flushDb();
 | 
			
		||||
    public void deleteAll() {
 | 
			
		||||
        Set<String> keys = redisTemplate.keys(  "*");
 | 
			
		||||
        redisTemplate.delete(keys.stream().filter(s -> !s.contains("online:token")).collect(Collectors.toList()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
| 
						 | 
				
			
			@ -72,7 +73,6 @@ public class RedisServiceImpl implements RedisService {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @SuppressWarnings("unchecked")
 | 
			
		||||
    public void saveCode(String key, Object val) {
 | 
			
		||||
        redisTemplate.opsForValue().set(key,val);
 | 
			
		||||
        redisTemplate.expire(key,expiration, TimeUnit.MINUTES);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -89,34 +89,34 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
 | 
			
		|||
                        "/**/*.js"
 | 
			
		||||
                ).anonymous()
 | 
			
		||||
 | 
			
		||||
                .antMatchers(HttpMethod.POST,"/auth/login").anonymous()
 | 
			
		||||
                .antMatchers(HttpMethod.GET,"/auth/code").anonymous()
 | 
			
		||||
                .antMatchers(HttpMethod.POST,"/auth/login").permitAll()
 | 
			
		||||
                .antMatchers(HttpMethod.DELETE,"/auth/logout").permitAll()
 | 
			
		||||
                .antMatchers(HttpMethod.GET,"/auth/code").permitAll()
 | 
			
		||||
                // 支付宝回调
 | 
			
		||||
                .antMatchers("/api/aliPay/return").anonymous()
 | 
			
		||||
                .antMatchers("/api/aliPay/notify").anonymous()
 | 
			
		||||
                .antMatchers("/api/aliPay/return").permitAll()
 | 
			
		||||
                .antMatchers("/api/aliPay/notify").permitAll()
 | 
			
		||||
 | 
			
		||||
                // swagger start
 | 
			
		||||
                .antMatchers("/swagger-ui.html").anonymous()
 | 
			
		||||
                .antMatchers("/swagger-resources/**").anonymous()
 | 
			
		||||
                .antMatchers("/webjars/**").anonymous()
 | 
			
		||||
                .antMatchers("/*/api-docs").anonymous()
 | 
			
		||||
                .antMatchers("/swagger-ui.html").permitAll()
 | 
			
		||||
                .antMatchers("/swagger-resources/**").permitAll()
 | 
			
		||||
                .antMatchers("/webjars/**").permitAll()
 | 
			
		||||
                .antMatchers("/*/api-docs").permitAll()
 | 
			
		||||
                // swagger end
 | 
			
		||||
 | 
			
		||||
                // 接口限流测试
 | 
			
		||||
                .antMatchers("/test/**").anonymous()
 | 
			
		||||
                .antMatchers("/test/**").permitAll()
 | 
			
		||||
                // 文件
 | 
			
		||||
                .antMatchers("/avatar/**").anonymous()
 | 
			
		||||
                .antMatchers("/file/**").anonymous()
 | 
			
		||||
                .antMatchers("/avatar/**").permitAll()
 | 
			
		||||
                .antMatchers("/file/**").permitAll()
 | 
			
		||||
 | 
			
		||||
                // 放行OPTIONS请求
 | 
			
		||||
                .antMatchers(HttpMethod.OPTIONS, "/**").anonymous()
 | 
			
		||||
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
 | 
			
		||||
 | 
			
		||||
                .antMatchers("/druid/**").anonymous()
 | 
			
		||||
                .antMatchers("/druid/**").permitAll()
 | 
			
		||||
                // 所有请求都需要认证
 | 
			
		||||
                .anyRequest().authenticated()
 | 
			
		||||
                // 防止iframe 造成跨域
 | 
			
		||||
                .and().headers().frameOptions().disable();
 | 
			
		||||
 | 
			
		||||
        httpSecurity
 | 
			
		||||
                .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.ImgResult;
 | 
			
		||||
import me.zhengjie.modules.security.security.JwtUser;
 | 
			
		||||
import me.zhengjie.modules.security.service.OnlineUserService;
 | 
			
		||||
import me.zhengjie.utils.EncryptUtils;
 | 
			
		||||
import me.zhengjie.modules.security.utils.JwtTokenUtil;
 | 
			
		||||
import me.zhengjie.utils.SecurityUtils;
 | 
			
		||||
import me.zhengjie.utils.StringUtils;
 | 
			
		||||
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.security.authentication.AccountExpiredException;
 | 
			
		||||
import org.springframework.security.core.userdetails.UserDetailsService;
 | 
			
		||||
import org.springframework.validation.annotation.Validated;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Zheng Jie
 | 
			
		||||
| 
						 | 
				
			
			@ -35,25 +37,25 @@ import org.springframework.web.bind.annotation.*;
 | 
			
		|||
@Api(tags = "系统:系统授权接口")
 | 
			
		||||
public class AuthenticationController {
 | 
			
		||||
 | 
			
		||||
    @Value("${jwt.header}")
 | 
			
		||||
    private String tokenHeader;
 | 
			
		||||
 | 
			
		||||
    private final JwtTokenUtil jwtTokenUtil;
 | 
			
		||||
 | 
			
		||||
    private final RedisService redisService;
 | 
			
		||||
 | 
			
		||||
    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.redisService = redisService;
 | 
			
		||||
        this.userDetailsService = userDetailsService;
 | 
			
		||||
        this.onlineUserService = onlineUserService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Log("用户登录")
 | 
			
		||||
    @ApiOperation("登录授权")
 | 
			
		||||
    @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());
 | 
			
		||||
| 
						 | 
				
			
			@ -74,10 +76,10 @@ public class AuthenticationController {
 | 
			
		|||
        if(!jwtUser.isEnabled()){
 | 
			
		||||
            throw new AccountExpiredException("账号已停用,请联系管理员");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 生成令牌
 | 
			
		||||
        final String token = jwtTokenUtil.generateToken(jwtUser);
 | 
			
		||||
 | 
			
		||||
        // 保存在线信息
 | 
			
		||||
        onlineUserService.save(jwtUser, token, request);
 | 
			
		||||
        // 返回 token
 | 
			
		||||
        return ResponseEntity.ok(new AuthInfo(token,jwtUser));
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -102,4 +104,11 @@ public class AuthenticationController {
 | 
			
		|||
        redisService.saveCode(uuid,result);
 | 
			
		||||
        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 lombok.extern.slf4j.Slf4j;
 | 
			
		||||
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.Value;
 | 
			
		||||
import org.springframework.data.redis.core.RedisTemplate;
 | 
			
		||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 | 
			
		||||
import org.springframework.security.core.context.SecurityContextHolder;
 | 
			
		||||
import org.springframework.security.core.userdetails.UserDetailsService;
 | 
			
		||||
| 
						 | 
				
			
			@ -21,38 +23,33 @@ import java.io.IOException;
 | 
			
		|||
@Component
 | 
			
		||||
public class JwtAuthorizationTokenFilter extends OncePerRequestFilter {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Value("${jwt.online}")
 | 
			
		||||
    private String onlineKey;
 | 
			
		||||
 | 
			
		||||
    private final UserDetailsService userDetailsService;
 | 
			
		||||
    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.jwtTokenUtil = jwtTokenUtil;
 | 
			
		||||
        this.tokenHeader = tokenHeader;
 | 
			
		||||
        this.redisTemplate = redisTemplate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
 | 
			
		||||
 | 
			
		||||
        final String requestHeader = request.getHeader(this.tokenHeader);
 | 
			
		||||
 | 
			
		||||
        String username = null;
 | 
			
		||||
        String authToken = null;
 | 
			
		||||
        if (requestHeader != null && requestHeader.startsWith("Bearer ")) {
 | 
			
		||||
            authToken = requestHeader.substring(7);
 | 
			
		||||
            try {
 | 
			
		||||
                username = jwtTokenUtil.getUsernameFromToken(authToken);
 | 
			
		||||
            } catch (ExpiredJwtException e) {
 | 
			
		||||
                log.error(e.getMessage());
 | 
			
		||||
            }
 | 
			
		||||
        String authToken = jwtTokenUtil.getToken(request);
 | 
			
		||||
        OnlineUser onlineUser = null;
 | 
			
		||||
        try {
 | 
			
		||||
            onlineUser = (OnlineUser)redisTemplate.opsForValue().get(onlineKey + authToken);
 | 
			
		||||
        } catch (ExpiredJwtException e) {
 | 
			
		||||
            log.error(e.getMessage());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
 | 
			
		||||
 | 
			
		||||
        if (onlineUser != null && SecurityContextHolder.getContext().getAuthentication() == null) {
 | 
			
		||||
            // 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 ;)
 | 
			
		||||
            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
 | 
			
		||||
            // the database compellingly. Again it's up to you ;)
 | 
			
		||||
            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.security.core.userdetails.UserDetails;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
| 
						 | 
				
			
			@ -103,6 +105,14 @@ public class JwtTokenUtil implements Serializable {
 | 
			
		|||
                .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) {
 | 
			
		||||
        JwtUser user = (JwtUser) userDetails;
 | 
			
		||||
        final Date created = getIssuedAtDateFromToken(token);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,8 +45,10 @@ spring:
 | 
			
		|||
jwt:
 | 
			
		||||
  header: Authorization
 | 
			
		||||
  secret: mySecret
 | 
			
		||||
  # token 过期时间 6个小时
 | 
			
		||||
  expiration: 21000000
 | 
			
		||||
  # token 过期时间/毫秒,6小时  1小时 = 3600000 毫秒
 | 
			
		||||
  expiration: 21600000
 | 
			
		||||
  # 在线用户key
 | 
			
		||||
  online: online-token
 | 
			
		||||
 | 
			
		||||
#是否允许生成代码,生产环境设置为false
 | 
			
		||||
generator:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,6 +49,8 @@ jwt:
 | 
			
		|||
  secret: mySecret
 | 
			
		||||
  # token 过期时间 2个小时
 | 
			
		||||
  expiration: 7200000
 | 
			
		||||
  # 在线用户key
 | 
			
		||||
  online: online-token
 | 
			
		||||
 | 
			
		||||
#是否允许生成代码,生产环境设置为false
 | 
			
		||||
generator:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue