用redis+jwt保存在线用户和获得在线用户列表、踢出用户示例
生活随笔
收集整理的這篇文章主要介紹了
用redis+jwt保存在线用户和获得在线用户列表、踢出用户示例
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
文章目錄
- redis工具類(lèi)
- 用戶(hù)實(shí)體類(lèi)
- token配置
- service層保存和查詢(xún)?cè)诰€用戶(hù)
- 工具類(lèi) 獲得用戶(hù)瀏覽器等其他信息
- controller層
redis工具類(lèi)
import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.RedisConnectionUtils; @Component @SuppressWarnings({"unchecked", "all"}) public class RedisUtils {private RedisTemplate<Object, Object> redisTemplate;@Value("${jwt.online-key}")private String onlineKey;public RedisUtils(RedisTemplate<Object, Object> redisTemplate) {this.redisTemplate = redisTemplate;}/*** 根據(jù) key 獲取過(guò)期時(shí)間* @param key 鍵 不能為null* @return 時(shí)間(秒) 返回0代表為永久有效*/public long getExpire(Object key) {return redisTemplate.getExpire(key, TimeUnit.SECONDS);}/*** 查找匹配key* @param pattern key* @return /*/public List<String> scan(String pattern) {ScanOptions options = ScanOptions.scanOptions().match(pattern).build();RedisConnectionFactory factory = redisTemplate.getConnectionFactory();RedisConnection rc = Objects.requireNonNull(factory).getConnection();Cursor<byte[]> cursor = rc.scan(options);List<String> result = new ArrayList<>();while (cursor.hasNext()) {result.add(new String(cursor.next()));}try {RedisConnectionUtils.releaseConnection(rc, factory);} catch (Exception e) {e.printStackTrace();}return result;}/*** 分頁(yè)查詢(xún) key* @param patternKey key* @param page 頁(yè)碼* @param size 每頁(yè)數(shù)目* @return /*/public List<String> findKeysForPage(String patternKey, int page, int size) {ScanOptions options = ScanOptions.scanOptions().match(patternKey).build();RedisConnectionFactory factory = redisTemplate.getConnectionFactory();RedisConnection rc = Objects.requireNonNull(factory).getConnection();Cursor<byte[]> cursor = rc.scan(options);List<String> result = new ArrayList<>(size);int tmpIndex = 0;int fromIndex = page * size;int toIndex = page * size + size;while (cursor.hasNext()) {if (tmpIndex >= fromIndex && tmpIndex < toIndex) {result.add(new String(cursor.next()));tmpIndex++;continue;}// 獲取到滿(mǎn)足條件的數(shù)據(jù)后,就可以退出了if (tmpIndex >= toIndex) {break;}tmpIndex++;cursor.next();}try {RedisConnectionUtils.releaseConnection(rc, factory);} catch (Exception e) {e.printStackTrace();}return result;}/*** 判斷key是否存在* @param key 鍵* @return true 存在 false不存在*/public boolean hasKey(String key) {try {return redisTemplate.hasKey(key);} catch (Exception e) {e.printStackTrace();return false;}}/*** 刪除緩存* @param key 可以傳一個(gè)值 或多個(gè)*/public void del(String... key) {if (key != null && key.length > 0) {if (key.length == 1) {redisTemplate.delete(key[0]);} else {redisTemplate.delete(CollectionUtils.arrayToList(key));}}}/*** 普通緩存獲取* @param key 鍵* @return 值*/public Object get(String key) {return key == null ? null : redisTemplate.opsForValue().get(key);}/*** 批量獲取* @param keys* @return*/public List<Object> multiGet(List<String> keys) {Object obj = redisTemplate.opsForValue().multiGet(Collections.singleton(keys));return null;}/*** 普通緩存放入* @param key 鍵* @param value 值* @return true成功 false失敗*/public boolean set(String key, Object value) {try {redisTemplate.opsForValue().set(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 普通緩存放入并設(shè)置時(shí)間* @param key 鍵* @param value 值* @param time 時(shí)間(秒) time要大于0 如果time小于等于0 將設(shè)置無(wú)限期* @return true成功 false 失敗*/public boolean set(String key, Object value, long time) {try {if (time > 0) {redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);} else {set(key, value);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 普通緩存放入并設(shè)置時(shí)間* @param key 鍵* @param value 值* @param time 時(shí)間* @param timeUnit 類(lèi)型* @return true成功 false 失敗*/public boolean set(String key, Object value, long time, TimeUnit timeUnit) {try {if (time > 0) {redisTemplate.opsForValue().set(key, value, time, timeUnit);} else {set(key, value);}return true;} catch (Exception e) {e.printStackTrace();return false;}}//省略其他操作map的方法 }用戶(hù)實(shí)體類(lèi)
@Data @AllArgsConstructor @NoArgsConstructor public class OnlineUser {private String userName;private String nickName;private String job;private String browser;private String ip;private String address;private String key;private Date loginTime;}token配置
securityproerties:
@Data @Configuration(proxyBeanMethods = false) @ConfigurationProperties(prefix = "jwt") public class SecurityProperties {/** Request Headers : Authorization */private String header;/** 令牌前綴,最后留個(gè)空格 Bearer */private String tokenStartWith;/** 必須使用最少88位的Base64對(duì)該令牌進(jìn)行編碼 */private String base64Secret;private String secret;/** 令牌過(guò)期時(shí)間 此處單位/毫秒 */private Long tokenValidityInSeconds;/** 在線用戶(hù) key,根據(jù) key 查詢(xún) redis 中在線用戶(hù)的數(shù)據(jù) */private String onlineKey;/** 驗(yàn)證碼 key */private String codeKey;public String getTokenStartWith() {return tokenStartWith + " ";} }其中Yml配置:
#jwt jwt:header: Authorization# 令牌前綴token-start-with: Bearersecret: k09BQnaF# 必須使用最少88位的Base64對(duì)該令牌進(jìn)行編碼base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI=# 令牌過(guò)期時(shí)間 此處單位/毫秒 ,默認(rèn)4小時(shí),可在此網(wǎng)站生成 https://www.convertworld.com/zh-hans/time/milliseconds.htmltoken-validity-in-seconds: 14400000# 在線用戶(hù)keyonline-key: online-token# 驗(yàn)證碼code-key: code-keyservice層保存和查詢(xún)?cè)诰€用戶(hù)
在線用戶(hù)層
@Service @Slf4j public class OnlineUserService {private final SecurityProperties properties;//這個(gè)特性類(lèi)的屬性在上面private RedisUtils redisUtils;public OnlineUserService(SecurityProperties properties, RedisUtils redisUtils) {this.properties = properties;this.redisUtils = redisUtils;}/*** 保存在線用戶(hù)信息* @param jwtUser /* @param token /* @param request /*/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(), jwtUser.getNickName(), job, browser, ip, address, EncryptUtils.desEncrypt(token), new Date());} catch (Exception e) {e.printStackTrace();}redisUtils.set(properties.getOnlineKey() + token, onlineUser, properties.getTokenValidityInSeconds() / 1000);}/*** 查詢(xún)?nèi)繑?shù)據(jù) 分頁(yè)* @param filter /* @param pageable /* @return /*/public Map<String, Object> getAll(String filter, int type, Pageable pageable) {List<OnlineUser> onlineUsers = getAll(filter, type);return PageUtil.toPage(PageUtil.toPage(pageable.getPageNumber(), pageable.getPageSize(), onlineUsers),onlineUsers.size());}/*** 查詢(xún)?nèi)繑?shù)據(jù),不分頁(yè)* @param filter /* @return /*/public List<OnlineUser> getAll(String filter, int type) {List<String> keys = null;if (type == 1) {keys = redisUtils.scan("m-online-token*");} else {keys = redisUtils.scan(properties.getOnlineKey() + "*");}Collections.reverse(keys);List<OnlineUser> onlineUsers = new ArrayList<>();for (String key : keys) {OnlineUser onlineUser = (OnlineUser) redisUtils.get(key);if (StringUtils.isNotBlank(filter)) {if (onlineUser.toString().contains(filter)) {onlineUsers.add(onlineUser);}} else {onlineUsers.add(onlineUser);}}onlineUsers.sort((o1, o2) -> o2.getLoginTime().compareTo(o1.getLoginTime()));return onlineUsers;}/*** 踢出用戶(hù)* @param key /* @throws Exception /*/public void kickOut(String key) throws Exception {key = properties.getOnlineKey() + EncryptUtils.desDecrypt(key);redisUtils.del(key);}/*** 踢出移動(dòng)端用戶(hù)* @param key /* @throws Exception /*/public void kickOutT(String key) throws Exception {String keyt = "m-online-token" + EncryptUtils.desDecrypt(key);redisUtils.del(keyt);}/*** 退出登錄* @param token /*/public void logout(String token) {String key = properties.getOnlineKey() + token;redisUtils.del(key);}/*** 檢測(cè)用戶(hù)是否在之前已經(jīng)登錄,已經(jīng)登錄踢下線* @param userName 用戶(hù)名*/public void checkLoginOnUser(String userName, String igoreToken) {List<OnlineUser> onlineUsers = getAll(userName, 0);if (onlineUsers == null || onlineUsers.isEmpty()) {return;}for (OnlineUser onlineUser : onlineUsers) {if (onlineUser.getUserName().equals(userName)) {try {String token = EncryptUtils.desDecrypt(onlineUser.getKey());if (StringUtils.isNotBlank(igoreToken) && !igoreToken.equals(token)) {this.kickOut(onlineUser.getKey());} else if (StringUtils.isBlank(igoreToken)) {this.kickOut(onlineUser.getKey());}} catch (Exception e) {log.error("checkUser is error", e);}}}}}工具類(lèi) 獲得用戶(hù)瀏覽器等其他信息
上面的StringUtils工具類(lèi)有一些獲取信息的方法:
import cn.hutool.http.HttpUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import eu.bitwalker.useragentutils.Browser; import eu.bitwalker.useragentutils.UserAgent;import javax.servlet.http.HttpServletRequest; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Calendar; import java.util.Date; public class StringUtils extends org.apache.commons.lang3.StringUtils {/*** 獲取ip地址*/public static String getIp(HttpServletRequest request) {String ip = request.getHeader("x-forwarded-for");if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}String comma = ",";String localhost = "127.0.0.1";if (ip.contains(comma)) {ip = ip.split(",")[0];}if (localhost.equals(ip)) {// 獲取本機(jī)真正的ip地址try {ip = InetAddress.getLocalHost().getHostAddress();} catch (UnknownHostException e) {e.printStackTrace();}}return ip;}/*** 根據(jù)ip獲取詳細(xì)地址*/public static String getCityInfo(String ip) {String api = String.format(YshopConstant.Url.IP_URL, ip);JSONObject object = JSONUtil.parseObj(HttpUtil.get(api));return object.get("addr", String.class);}//獲取用戶(hù)瀏覽器名字public static String getBrowser(HttpServletRequest request) {UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));Browser browser = userAgent.getBrowser();return browser.getName();}/*** 獲得當(dāng)天是周幾*/public static String getWeekDay() {String[] weekDays = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};Calendar cal = Calendar.getInstance();cal.setTime(new Date());int w = cal.get(Calendar.DAY_OF_WEEK) - 1;if (w < 0) {w = 0;}return weekDays[w];} }controller層
@RestController @RequestMapping("/auth/online") @Api(tags = "系統(tǒng):在線用戶(hù)管理") public class OnlineController {private final OnlineUserService onlineUserService;public OnlineController(OnlineUserService onlineUserService) {this.onlineUserService = onlineUserService;}@ApiOperation("查詢(xún)?cè)诰€用戶(hù)")@GetMapping@PreAuthorize("@el.check()")public ResponseEntity<Object> getAll(@RequestParam(value = "filter", defaultValue = "") String filter,@RequestParam(value = "type", defaultValue = "0") int type,Pageable pageable) {return new ResponseEntity<>(onlineUserService.getAll(filter, type, pageable), HttpStatus.OK);}@ApiOperation("踢出用戶(hù)")@DeleteMapping@PreAuthorize("@el.check()")public ResponseEntity<Object> delete(@RequestBody Set<String> keys) throws Exception {for (String key : keys) {onlineUserService.kickOut(key);}return new ResponseEntity<>(HttpStatus.OK);}@ForbidSubmit@ApiOperation("踢出移動(dòng)端用戶(hù)")@PostMapping("/delete")@PreAuthorize("@el.check()")public ResponseEntity<Object> deletet(@RequestBody Set<String> keys) throws Exception {for (String key : keys) {onlineUserService.kickOutT(key);}return new ResponseEntity<>(HttpStatus.OK);}總結(jié)
以上是生活随笔為你收集整理的用redis+jwt保存在线用户和获得在线用户列表、踢出用户示例的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 查看动态代理生成的代理类字节码
- 下一篇: 自定义线程池内置线程池的使用 Threa