Commit aa3d7e969916d82e9ad37be4d7e42fa7dbf44db5

Authored by 易文鹏
1 parent 6947996f

feat:权限控制

src/main/java/com/huaheng/common/constant/ShiroRedisConstants.java 0 → 100644
  1 +package com.huaheng.common.constant;
  2 +
  3 +public interface ShiroRedisConstants
  4 +{
  5 + public static final String DEFAULT_SESSION_KEY_PREFIX = "shiro:redisCache:sessionId:";
  6 +
  7 + public String keyPrefix = DEFAULT_SESSION_KEY_PREFIX;
  8 +}
... ...
src/main/java/com/huaheng/common/exception/user/UserPasswordRetryLimitCountException.java
... ... @@ -2,15 +2,18 @@ package com.huaheng.common.exception.user;
2 2  
3 3 /**
4 4 * 用户错误记数异常类
5   - *
  5 + *
6 6 * @author huaheng
7 7 */
8   -public class UserPasswordRetryLimitCountException extends UserException
9   -{
  8 +public class UserPasswordRetryLimitCountException extends UserException {
10 9 private static final long serialVersionUID = 1L;
11 10  
12   - public UserPasswordRetryLimitCountException(int retryLimitCount, String password)
13   - {
14   - super("user.password.retry.limit.count", new Object[] { retryLimitCount, password });
  11 + public UserPasswordRetryLimitCountException(int retryLimitCount, String password) {
  12 + super("user.password.retry.limit.count", new Object[]{retryLimitCount, password});
  13 + }
  14 +
  15 +
  16 + public UserPasswordRetryLimitCountException(int retryLimitCount) {
  17 + super("user.password.retry.limit.count", new Object[]{retryLimitCount});
15 18 }
16 19 }
... ...
src/main/java/com/huaheng/common/utils/RedisUtils.java 0 → 100644
  1 +package com.huaheng.common.utils;
  2 +
  3 +import com.huaheng.common.constant.ShiroRedisConstants;
  4 +import org.apache.shiro.dao.DataAccessException;
  5 +import org.springframework.beans.factory.annotation.Autowired;
  6 +import org.springframework.data.redis.connection.RedisConnection;
  7 +import org.springframework.data.redis.core.Cursor;
  8 +import org.springframework.data.redis.core.RedisCallback;
  9 +import org.springframework.data.redis.core.RedisTemplate;
  10 +import org.springframework.data.redis.core.ScanOptions;
  11 +import org.springframework.stereotype.Component;
  12 +import org.springframework.util.CollectionUtils;
  13 +
  14 +import java.util.*;
  15 +import java.util.concurrent.TimeUnit;
  16 +
  17 +@Component
  18 +public class RedisUtils {
  19 + /**
  20 + * 注入自定义redisTemplate bean
  21 + */
  22 + @Autowired
  23 + private RedisTemplate<String, Object> redisTemplate;
  24 +
  25 + @Autowired
  26 + private RedisTemplate<String, Object> shiroRedisTemplate;
  27 +
  28 + public static String getRedisSessionKey(String SessionId) {
  29 + return ShiroRedisConstants.keyPrefix + SessionId;
  30 + }
  31 + /*
  32 + * @Autowired private StringRedisTemplate stringRedisTemplate;
  33 + */
  34 +
  35 + /**
  36 + * 指定缓存失效时间
  37 + *
  38 + * @param isShiroRedis 是否属于shiroredis缓存
  39 + * @param key 键
  40 + * @param time 时间(秒)
  41 + * @return
  42 + */
  43 + public boolean expire(Boolean isShiroRedis, String key, long time) {
  44 + try {
  45 + if (isShiroRedis) {
  46 + if (time > 0) {
  47 +
  48 + shiroRedisTemplate.expire(key, time, TimeUnit.MILLISECONDS);
  49 +
  50 + }
  51 + } else {
  52 + if (time > 0) {
  53 +
  54 + redisTemplate.expire(key, time, TimeUnit.MILLISECONDS);
  55 +
  56 + }
  57 + }
  58 +
  59 + return true;
  60 + } catch (Exception e) {
  61 + e.printStackTrace();
  62 + return false;
  63 + }
  64 + }
  65 +
  66 + /**
  67 + * 根据key获取过期时间
  68 + *
  69 + * @param isShiroRedis shiroRedisCache
  70 + * @param key 键 不能为null
  71 + * @return 时间(秒) 返回0代表为永久有效
  72 + */
  73 + public long getExpire(Boolean isShiroRedis, String key) {
  74 + return isShiroRedis ? shiroRedisTemplate.getExpire(key, TimeUnit.MILLISECONDS)
  75 + : redisTemplate.getExpire(key, TimeUnit.MILLISECONDS);
  76 + }
  77 +
  78 + /**
  79 + * 判断key是否存在
  80 + *
  81 + * @param isShiroRedis shiroRedisCache
  82 + * @param key 键
  83 + * @return true 存在 false不存在
  84 + */
  85 + public boolean hasKey(Boolean isShiroRedis, String key) {
  86 + try {
  87 + return isShiroRedis ? shiroRedisTemplate.hasKey(key) : redisTemplate.hasKey(key);
  88 + } catch (Exception e) {
  89 + e.printStackTrace();
  90 + return false;
  91 + }
  92 + }
  93 +
  94 + /**
  95 + * 删除缓存
  96 + *
  97 + * @param key 可以传一个值 或多个
  98 + */
  99 + @SuppressWarnings("unchecked")
  100 + public void del(Boolean isShiroRedis, String... key) {
  101 + if (isShiroRedis) {
  102 + if (key != null && key.length > 0) {
  103 + if (key.length == 1) {
  104 + shiroRedisTemplate.delete(key[0]);
  105 + } else {
  106 + shiroRedisTemplate.delete(CollectionUtils.arrayToList(key));
  107 + }
  108 + }
  109 + } else {
  110 +
  111 + if (key != null && key.length > 0) {
  112 + if (key.length == 1) {
  113 + redisTemplate.delete(key[0]);
  114 + } else {
  115 + redisTemplate.delete(CollectionUtils.arrayToList(key));
  116 + }
  117 + }
  118 + }
  119 +
  120 + }
  121 +
  122 + /**
  123 + * 批量删除key
  124 + *
  125 + * @param keys
  126 + */
  127 + @SuppressWarnings({"rawtypes", "unchecked"})
  128 + public void del(Boolean isShiroRedis, Collection keys) {
  129 +
  130 + if (isShiroRedis) {
  131 + shiroRedisTemplate.delete(keys);
  132 + } else {
  133 + redisTemplate.delete(keys);
  134 + }
  135 +
  136 + }
  137 +
  138 + /**
  139 + * 使用scan命令 查询某些前缀的key
  140 + *
  141 + * @param key
  142 + * @return
  143 + */
  144 + public Set<String> scan(Boolean isShiroRedis, String key) {
  145 + if (isShiroRedis) {
  146 + Set<String> execute = this.shiroRedisTemplate.execute(new RedisCallback<Set<String>>() {
  147 +
  148 + @Override
  149 + public Set<String> doInRedis(RedisConnection connection) throws DataAccessException {
  150 +
  151 + Set<String> binaryKeys = new HashSet<>();
  152 +
  153 + Cursor<byte[]> cursor = connection
  154 + .scan(new ScanOptions.ScanOptionsBuilder().match(key).count(1000).build());
  155 + while (cursor.hasNext()) {
  156 + binaryKeys.add(new String(cursor.next()));
  157 + }
  158 + return binaryKeys;
  159 + }
  160 + });
  161 + return execute;
  162 + } else {
  163 +
  164 + Set<String> execute = this.redisTemplate.execute(new RedisCallback<Set<String>>() {
  165 +
  166 + @Override
  167 + public Set<String> doInRedis(RedisConnection connection) throws DataAccessException {
  168 +
  169 + Set<String> binaryKeys = new HashSet<>();
  170 +
  171 + Cursor<byte[]> cursor = connection
  172 + .scan(new ScanOptions.ScanOptionsBuilder().match(key).count(1000).build());
  173 + while (cursor.hasNext()) {
  174 + binaryKeys.add(new String(cursor.next()));
  175 + }
  176 + return binaryKeys;
  177 + }
  178 + });
  179 + return execute;
  180 + }
  181 +
  182 + }
  183 +
  184 + /**
  185 + * 使用scan命令 查询某些前缀的key 有多少个 可用来获取当前session数量,也就是在线用户
  186 + *
  187 + * @param key
  188 + * @return
  189 + */
  190 + public Long scanSize(Boolean isShiroRedis, String key) {
  191 + if (isShiroRedis) {
  192 + long dbSize = this.shiroRedisTemplate.execute(new RedisCallback<Long>() {
  193 +
  194 + @Override
  195 + public Long doInRedis(RedisConnection connection) throws DataAccessException {
  196 + long count = 0L;
  197 + Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match(key).count(1000).build());
  198 + while (cursor.hasNext()) {
  199 + cursor.next();
  200 + count++;
  201 + }
  202 + return count;
  203 + }
  204 + });
  205 + return dbSize;
  206 + } else {
  207 + long dbSize = this.redisTemplate.execute(new RedisCallback<Long>() {
  208 +
  209 + @Override
  210 + public Long doInRedis(RedisConnection connection) throws DataAccessException {
  211 + long count = 0L;
  212 + Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match(key).count(1000).build());
  213 + while (cursor.hasNext()) {
  214 + cursor.next();
  215 + count++;
  216 + }
  217 + return count;
  218 + }
  219 + });
  220 + return dbSize;
  221 + }
  222 + }
  223 +
  224 + // ============================String(字符串)=============================
  225 +
  226 + /**
  227 + * 普通缓存获取
  228 + *
  229 + * @param key 键
  230 + * @return 值
  231 + */
  232 + public Object get(Boolean isShiroRedis, String key) {
  233 + return isShiroRedis ? (key == null ? null : shiroRedisTemplate.opsForValue().get(key))
  234 + : (key == null ? null : redisTemplate.opsForValue().get(key));
  235 + }
  236 +
  237 + /**
  238 + * 普通缓存放入
  239 + *
  240 + * @param key 键
  241 + * @param value 值
  242 + * @return true成功 false失败
  243 + */
  244 + public boolean set(Boolean isShiroRedis, String key, Object value) {
  245 + try {
  246 +
  247 + if (isShiroRedis) {
  248 +
  249 + shiroRedisTemplate.opsForValue().set(key, value);
  250 + } else {
  251 + redisTemplate.opsForValue().set(key, value);
  252 + }
  253 +
  254 + return true;
  255 + } catch (Exception e) {
  256 + e.printStackTrace();
  257 + return false;
  258 + }
  259 + }
  260 +
  261 + /**
  262 + * 普通缓存放入并设置时间
  263 + *
  264 + * @param key 键
  265 + * @param value 值
  266 + * @param time 时间(分钟) time要大于0 如果time小于等于0 将设置无限期
  267 + * @return true成功 false 失败
  268 + */
  269 + public boolean set(Boolean isShiroRedis, String key, Object value, long time) {
  270 + try {
  271 + if (isShiroRedis) {
  272 + if (time > 0) {
  273 + shiroRedisTemplate.opsForValue().set(key, value, time, TimeUnit.MILLISECONDS);
  274 + } else {
  275 + set(isShiroRedis, key, value);
  276 + }
  277 + } else {
  278 +
  279 + if (time > 0) {
  280 + redisTemplate.opsForValue().set(key, value, time, TimeUnit.MILLISECONDS);
  281 + } else {
  282 + set(isShiroRedis, key, value);
  283 + }
  284 + }
  285 + return true;
  286 + } catch (Exception e) {
  287 + e.printStackTrace();
  288 + return false;
  289 + }
  290 + }
  291 +
  292 + /**
  293 + * 递增
  294 + *
  295 + * @param key 键
  296 + * @param delta 要增加几(大于0)
  297 + * @return
  298 + */
  299 + public long incr(Boolean isShiroRedis, String key, long delta) {
  300 + if (delta < 0) {
  301 + throw new RuntimeException("递增因子必须大于0");
  302 + }
  303 + return isShiroRedis ? shiroRedisTemplate.opsForValue().increment(key, delta)
  304 + : redisTemplate.opsForValue().increment(key, delta);
  305 + }
  306 +
  307 + /**
  308 + * 递减
  309 + *
  310 + * @param key 键
  311 + * @param delta 要减少几(小于0)
  312 + * @return
  313 + */
  314 + public long decr(Boolean isShiroRedis, String key, long delta) {
  315 + if (delta < 0) {
  316 + throw new RuntimeException("递减因子必须大于0");
  317 + }
  318 + return isShiroRedis ? shiroRedisTemplate.opsForValue().increment(key, -delta)
  319 + : redisTemplate.opsForValue().increment(key, -delta);
  320 + }
  321 + // ================================Hash(哈希)=================================
  322 +
  323 + /**
  324 + * HashGet
  325 + *
  326 + * @param key 键 不能为null
  327 + * @param item 项 不能为null
  328 + * @return 值
  329 + */
  330 + public Object hget(Boolean isShiroRedis, String key, String item) {
  331 + return isShiroRedis ? shiroRedisTemplate.opsForHash().get(key, item)
  332 + : redisTemplate.opsForHash().get(key, item);
  333 + }
  334 +
  335 + /**
  336 + * 获取hashKey对应的所有键值
  337 + *
  338 + * @param key 键
  339 + * @return 对应的多个键值
  340 + */
  341 + public Map<Object, Object> hmget(Boolean isShiroRedis, String key) {
  342 + return isShiroRedis ? shiroRedisTemplate.opsForHash().entries(key) : redisTemplate.opsForHash().entries(key);
  343 + }
  344 +
  345 + /**
  346 + * HashSet
  347 + *
  348 + * @param key 键
  349 + * @param map 对应多个键值
  350 + * @return true 成功 false 失败
  351 + */
  352 + public boolean hmset(Boolean isShiroRedis, String key, Map<String, Object> map) {
  353 + try {
  354 +
  355 + if (isShiroRedis) {
  356 +
  357 + shiroRedisTemplate.opsForHash().putAll(key, map);
  358 + } else {
  359 + redisTemplate.opsForHash().putAll(key, map);
  360 + }
  361 +
  362 + return true;
  363 + } catch (Exception e) {
  364 + e.printStackTrace();
  365 + return false;
  366 + }
  367 + }
  368 +
  369 + /**
  370 + * HashSet 并设置时间
  371 + *
  372 + * @param isShiroRedis 是否为shiroredis缓存
  373 + * @param key 键
  374 + * @param map 对应多个键值
  375 + * @param time 时间(秒)
  376 + * @return true成功 false失败
  377 + */
  378 + public boolean hmset(Boolean isShiroRedis, String key, Map<String, Object> map, long time) {
  379 + try {
  380 + if (isShiroRedis) {
  381 + shiroRedisTemplate.opsForHash().putAll(key, map);
  382 + if (time > 0) {
  383 + expire(isShiroRedis, key, time);
  384 + }
  385 + } else {
  386 + redisTemplate.opsForHash().putAll(key, map);
  387 + if (time > 0) {
  388 + expire(isShiroRedis, key, time);
  389 + }
  390 + }
  391 +
  392 + return true;
  393 + } catch (Exception e) {
  394 + e.printStackTrace();
  395 + return false;
  396 + }
  397 + }
  398 +
  399 + /**
  400 + * 向一张hash表中放入数据,如果不存在将创建
  401 + *
  402 + * @param key 键
  403 + * @param item 项
  404 + * @param value 值
  405 + * @return true 成功 false失败
  406 + */
  407 + public boolean hset(Boolean isShiroRedis, String key, String item, Object value) {
  408 + try {
  409 + if (isShiroRedis) {
  410 + shiroRedisTemplate.opsForHash().put(key, item, value);
  411 + } else {
  412 + redisTemplate.opsForHash().put(key, item, value);
  413 + }
  414 +
  415 + return true;
  416 + } catch (Exception e) {
  417 + e.printStackTrace();
  418 + return false;
  419 + }
  420 + }
  421 +
  422 + /**
  423 + * 向一张hash表中放入数据,如果不存在将创建
  424 + *
  425 + * @param
  426 + * @param key 键
  427 + * @param item 项
  428 + * @param value 值
  429 + * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
  430 + * @return true 成功 false失败
  431 + */
  432 + public boolean hset(Boolean isShiroRedis, String key, String item, Object value, long time) {
  433 + try {
  434 + if (isShiroRedis) {
  435 + shiroRedisTemplate.opsForHash().put(key, item, value);
  436 + if (time > 0) {
  437 + expire(isShiroRedis, key, time);
  438 + }
  439 + } else {
  440 + redisTemplate.opsForHash().put(key, item, value);
  441 + if (time > 0) {
  442 + expire(isShiroRedis, key, time);
  443 + }
  444 + }
  445 +
  446 + return true;
  447 + } catch (Exception e) {
  448 + e.printStackTrace();
  449 + return false;
  450 + }
  451 + }
  452 +
  453 + /**
  454 + * 删除hash表中的值
  455 + *
  456 + * @param key 键 不能为null
  457 + * @param item 项 可以使多个 不能为null
  458 + */
  459 + public void hdel(Boolean isShiroRedis, String key, Object... item) {
  460 +
  461 + if (isShiroRedis) {
  462 + shiroRedisTemplate.opsForHash().delete(key, item);
  463 + } else {
  464 + redisTemplate.opsForHash().delete(key, item);
  465 + }
  466 +
  467 + }
  468 +
  469 + /**
  470 + * 判断hash表中是否有该项的值
  471 + *
  472 + * @param key 键 不能为null
  473 + * @param item 项 不能为null
  474 + * @return true 存在 false不存在
  475 + */
  476 + public boolean hHasKey(String key, String item) {
  477 + return redisTemplate.opsForHash().hasKey(key, item);
  478 + }
  479 +
  480 + /**
  481 + * hash递增 如果不存在,就会创建一个 并把新增后的值返回
  482 + *
  483 + * @param key 键
  484 + * @param item 项
  485 + * @param by 要增加几(大于0)
  486 + * @return
  487 + */
  488 + public double hincr(String key, String item, double by) {
  489 + return redisTemplate.opsForHash().increment(key, item, by);
  490 + }
  491 +
  492 + /**
  493 + * hash递减
  494 + *
  495 + * @param key 键
  496 + * @param item 项
  497 + * @param by 要减少记(小于0)
  498 + * @return
  499 + */
  500 + public double hdecr(String key, String item, double by) {
  501 + return redisTemplate.opsForHash().increment(key, item, -by);
  502 + }
  503 + // ============================Set(集合)=============================
  504 +
  505 + /**
  506 + * 根据key获取Set中的所有值
  507 + *
  508 + * @param key 键
  509 + * @return
  510 + */
  511 + public Set<Object> sGet(String key) {
  512 + try {
  513 + return redisTemplate.opsForSet().members(key);
  514 + } catch (Exception e) {
  515 + e.printStackTrace();
  516 + return null;
  517 + }
  518 + }
  519 +
  520 + /**
  521 + * 根据value从一个set中查询,是否存在
  522 + *
  523 + * @param key 键
  524 + * @param value 值
  525 + * @return true 存在 false不存在
  526 + */
  527 + public boolean sHasKey(String key, Object value) {
  528 + try {
  529 + return redisTemplate.opsForSet().isMember(key, value);
  530 + } catch (Exception e) {
  531 + e.printStackTrace();
  532 + return false;
  533 + }
  534 + }
  535 +
  536 + /**
  537 + * 将数据放入set缓存
  538 + *
  539 + * @param key 键
  540 + * @param values 值 可以是多个
  541 + * @return 成功个数
  542 + */
  543 + public long sSet(String key, Object... values) {
  544 + try {
  545 + return redisTemplate.opsForSet().add(key, values);
  546 + } catch (Exception e) {
  547 + e.printStackTrace();
  548 + return 0;
  549 + }
  550 + }
  551 +
  552 + /**
  553 + * 将set数据放入缓存
  554 + *
  555 + * @param key 键
  556 + * @param time 时间(秒)
  557 + * @param values 值 可以是多个
  558 + * @return 成功个数
  559 + */
  560 + public long sSetAndTime(Boolean isShiroRedis, String key, long time, Object... values) {
  561 + try {
  562 +
  563 + if (isShiroRedis) {
  564 + Long count = shiroRedisTemplate.opsForSet().add(key, values);
  565 + if (time > 0) {
  566 + expire(isShiroRedis, key, time);
  567 + }
  568 + return count;
  569 + } else {
  570 + Long count = redisTemplate.opsForSet().add(key, values);
  571 + if (time > 0) {
  572 + expire(isShiroRedis, key, time);
  573 + }
  574 + return count;
  575 + }
  576 +
  577 + } catch (Exception e) {
  578 + e.printStackTrace();
  579 + return 0;
  580 + }
  581 + }
  582 +
  583 + /**
  584 + * 获取set缓存的长度
  585 + *
  586 + * @param key 键
  587 + * @return
  588 + */
  589 + public long sGetSetSize(String key) {
  590 + try {
  591 + return redisTemplate.opsForSet().size(key);
  592 + } catch (Exception e) {
  593 + e.printStackTrace();
  594 + return 0;
  595 + }
  596 + }
  597 +
  598 + /**
  599 + * 移除值为value的
  600 + *
  601 + * @param key 键
  602 + * @param values 值 可以是多个
  603 + * @return 移除的个数
  604 + */
  605 + public long setRemove(String key, Object... values) {
  606 + try {
  607 + Long count = redisTemplate.opsForSet().remove(key, values);
  608 + return count;
  609 + } catch (Exception e) {
  610 + e.printStackTrace();
  611 + return 0;
  612 + }
  613 + }
  614 + // ===============================List(列表)=================================
  615 +
  616 + /**
  617 + * 获取list缓存的内容
  618 + *
  619 + * @param key 键
  620 + * @param start 开始
  621 + * @param end 结束 0 到 -1代表所有值
  622 + * @return
  623 + */
  624 + public List<Object> lGet(String key, long start, long end) {
  625 + try {
  626 + return redisTemplate.opsForList().range(key, start, end);
  627 + } catch (Exception e) {
  628 + e.printStackTrace();
  629 + return null;
  630 + }
  631 + }
  632 +
  633 + /**
  634 + * 获取list缓存的长度
  635 + *
  636 + * @param key 键
  637 + * @return
  638 + */
  639 + public long lGetListSize(String key) {
  640 + try {
  641 + return redisTemplate.opsForList().size(key);
  642 + } catch (Exception e) {
  643 + e.printStackTrace();
  644 + return 0;
  645 + }
  646 + }
  647 +
  648 + /**
  649 + * 通过索引 获取list中的值
  650 + *
  651 + * @param key 键
  652 + * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
  653 + * @return
  654 + */
  655 + public Object lGetIndex(String key, long index) {
  656 + try {
  657 + return redisTemplate.opsForList().index(key, index);
  658 + } catch (Exception e) {
  659 + e.printStackTrace();
  660 + return null;
  661 + }
  662 + }
  663 +
  664 + /**
  665 + * 将list放入缓存
  666 + *
  667 + * @param key 键
  668 + * @param value 值
  669 + * @return
  670 + */
  671 + public boolean lSet(String key, Object value) {
  672 + try {
  673 + redisTemplate.opsForList().rightPush(key, value);
  674 + return true;
  675 + } catch (Exception e) {
  676 + e.printStackTrace();
  677 + return false;
  678 + }
  679 + }
  680 +
  681 + /**
  682 + * 将list放入缓存
  683 + *
  684 + * @param isShiroRedis 是否shiroredis缓存
  685 + * @param key 键
  686 + * @param value 值
  687 + * @param time 时间(秒)
  688 + * @return
  689 + */
  690 + public boolean lSet(Boolean isShiroRedis, String key, Object value, long time) {
  691 + try {
  692 + if (isShiroRedis) {
  693 + shiroRedisTemplate.opsForList().rightPush(key, value);
  694 + if (time > 0) {
  695 + expire(isShiroRedis, key, time);
  696 + }
  697 +
  698 + } else {
  699 + redisTemplate.opsForList().rightPush(key, value);
  700 + if (time > 0) {
  701 + expire(isShiroRedis, key, time);
  702 + }
  703 + }
  704 +
  705 + return true;
  706 + } catch (Exception e) {
  707 + e.printStackTrace();
  708 + return false;
  709 + }
  710 + }
  711 +
  712 + /**
  713 + * 将list放入缓存
  714 + *
  715 + * @param key 键
  716 + * @param value 值
  717 + * @return
  718 + */
  719 + public boolean lSet(String key, List<Object> value) {
  720 + try {
  721 + redisTemplate.opsForList().rightPushAll(key, value);
  722 + return true;
  723 + } catch (Exception e) {
  724 + e.printStackTrace();
  725 + return false;
  726 + }
  727 + }
  728 +
  729 + /**
  730 + * 将list放入缓存
  731 + *
  732 + * @param isShiroRedis shiroredisCache
  733 + * @param key 键
  734 + * @param value 值
  735 + * @param time 时间(秒)
  736 + * @return
  737 + */
  738 + public boolean lSet(Boolean isShiroRedis, String key, List<Object> value, long time) {
  739 + try {
  740 +
  741 + if (isShiroRedis) {
  742 + shiroRedisTemplate.opsForList().rightPushAll(key, value);
  743 + if (time > 0) {
  744 + expire(isShiroRedis, key, time);
  745 + }
  746 + } else {
  747 + redisTemplate.opsForList().rightPushAll(key, value);
  748 + if (time > 0) {
  749 + expire(isShiroRedis, key, time);
  750 + }
  751 + }
  752 +
  753 + return true;
  754 + } catch (Exception e) {
  755 + e.printStackTrace();
  756 + return false;
  757 + }
  758 + }
  759 +
  760 + /**
  761 + * 根据索引修改list中的某条数据
  762 + *
  763 + * @param key 键
  764 + * @param index 索引
  765 + * @param value 值
  766 + * @return
  767 + */
  768 + public boolean lUpdateIndex(String key, long index, Object value) {
  769 + try {
  770 + redisTemplate.opsForList().set(key, index, value);
  771 + return true;
  772 + } catch (Exception e) {
  773 + e.printStackTrace();
  774 + return false;
  775 + }
  776 + }
  777 +
  778 + /**
  779 + * 移除N个值为value
  780 + *
  781 + * @param key 键
  782 + * @param count 移除多少个
  783 + * @param value 值
  784 + * @return 移除的个数
  785 + */
  786 + public long lRemove(String key, long count, Object value) {
  787 + try {
  788 + Long remove = redisTemplate.opsForList().remove(key, count, value);
  789 + return remove;
  790 + } catch (Exception e) {
  791 + e.printStackTrace();
  792 + return 0;
  793 + }
  794 + }
  795 +}
... ...
src/main/java/com/huaheng/framework/config/CacheManagerConfig.java 0 → 100644
  1 +package com.huaheng.framework.config;
  2 +
  3 +import com.huaheng.common.utils.RedisUtils;
  4 +import com.huaheng.common.utils.StringUtils;
  5 +import com.huaheng.framework.redis.RedisCacheManager;
  6 +import org.apache.commons.io.IOUtils;
  7 +import org.apache.shiro.cache.ehcache.EhCacheManager;
  8 +import org.apache.shiro.config.ConfigurationException;
  9 +import org.apache.shiro.io.ResourceUtils;
  10 +import org.springframework.beans.factory.annotation.Autowired;
  11 +import org.springframework.context.annotation.Bean;
  12 +import org.springframework.context.annotation.Configuration;
  13 +
  14 +import java.io.ByteArrayInputStream;
  15 +import java.io.IOException;
  16 +import java.io.InputStream;
  17 +
  18 +@Configuration
  19 +public class CacheManagerConfig
  20 +{
  21 + @Autowired
  22 + private RedisUtils redisUtils;
  23 +
  24 + /**
  25 + * 缓存管理器 使用Ehcache实现
  26 + */
  27 + @Bean
  28 + public EhCacheManager getEhCacheManager()
  29 + {
  30 +
  31 + net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.getCacheManager("huaheng");
  32 + EhCacheManager em = new EhCacheManager();
  33 + if (StringUtils.isNull(cacheManager))
  34 + {
  35 + em.setCacheManager(new net.sf.ehcache.CacheManager(
  36 + getCacheManagerConfigFileInputStream("classpath:ehcache/ehcache-shiro.xml")));
  37 +
  38 + return em;
  39 + }
  40 + else
  41 + {
  42 + em.setCacheManager(cacheManager);
  43 + return em;
  44 + }
  45 + }
  46 +
  47 + /**
  48 + * 返回配置文件流 避免ehcache配置文件一直被占用,无法完全销毁项目重新部署
  49 + */
  50 + protected InputStream getCacheManagerConfigFileInputStream(String configFile)
  51 + {
  52 +
  53 + InputStream inputStream = null;
  54 + try
  55 + {
  56 + inputStream = ResourceUtils.getInputStreamForPath(configFile);
  57 + byte[] b = IOUtils.toByteArray(inputStream);
  58 + InputStream in = new ByteArrayInputStream(b);
  59 + return in;
  60 + }
  61 + catch (IOException e)
  62 + {
  63 + throw new ConfigurationException(
  64 + "Unable to obtain input stream for cacheManagerConfigFile [" + configFile + "]", e);
  65 + }
  66 + finally
  67 + {
  68 + IOUtils.closeQuietly(inputStream);
  69 + }
  70 + }
  71 +
  72 + /**
  73 + * shiro缓存管理器; 需要添加到securityManager中
  74 + *
  75 + * @return
  76 + */
  77 + @Bean
  78 + public RedisCacheManager getRedisCacheManager()
  79 + {
  80 + RedisCacheManager redisCacheManager = new RedisCacheManager();
  81 + redisCacheManager.setRedisUtils(redisUtils);
  82 + // redis中针对不同用户缓存
  83 + redisCacheManager.setPrincipalIdFieldName("loginName");
  84 + // 用户权限信息缓存时间
  85 + redisCacheManager.setExpire(30 * 60 * 1000);
  86 +
  87 + return redisCacheManager;
  88 + }
  89 +}
... ...
src/main/java/com/huaheng/framework/config/RedisConfig.java 0 → 100644
  1 +package com.huaheng.framework.config;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonAutoDetect;
  4 +import com.fasterxml.jackson.annotation.PropertyAccessor;
  5 +import com.fasterxml.jackson.databind.ObjectMapper;
  6 +import com.huaheng.framework.redis.serializer.SerializeUtils;
  7 +import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
  8 +import org.springframework.beans.factory.annotation.Value;
  9 +import org.springframework.boot.context.properties.ConfigurationProperties;
  10 +import org.springframework.cache.CacheManager;
  11 +import org.springframework.cache.annotation.CachingConfigurerSupport;
  12 +import org.springframework.cache.annotation.EnableCaching;
  13 +import org.springframework.cache.interceptor.KeyGenerator;
  14 +import org.springframework.context.annotation.Bean;
  15 +import org.springframework.context.annotation.Configuration;
  16 +import org.springframework.context.annotation.Scope;
  17 +import org.springframework.data.redis.cache.RedisCacheConfiguration;
  18 +import org.springframework.data.redis.cache.RedisCacheManager;
  19 +import org.springframework.data.redis.connection.RedisPassword;
  20 +import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
  21 +import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
  22 +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
  23 +import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
  24 +import org.springframework.data.redis.core.RedisTemplate;
  25 +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
  26 +import org.springframework.data.redis.serializer.RedisSerializationContext;
  27 +import org.springframework.data.redis.serializer.RedisSerializer;
  28 +import org.springframework.data.redis.serializer.StringRedisSerializer;
  29 +
  30 +import java.lang.reflect.Method;
  31 +import java.time.Duration;
  32 +
  33 +@Configuration
  34 +@EnableCaching // 开启缓存支持
  35 +public class RedisConfig extends CachingConfigurerSupport
  36 +{
  37 + @Value("${redis.database}")
  38 + private int database;
  39 +
  40 + @Value("${redis.host}")
  41 + private String host;
  42 +
  43 + @Value("${redis.port}")
  44 + private int port;
  45 +
  46 + @Value("${redis.password}")
  47 + private String password;
  48 +
  49 + @Value("${redis.ssl}")
  50 + private Boolean ssl;
  51 +
  52 + @Value("${redis.lettuce.pool.max-idle}")
  53 + private int maxIdle;
  54 +
  55 + @Value("${redis.lettuce.pool.min-idle}")
  56 + private int minIdle;
  57 +
  58 + @Value("${redis.lettuce.pool.max-total}")
  59 + private int maxTotal;
  60 +
  61 + @Value("${redis.lettuce.pool.max-waitMillis}")
  62 + private long maxWaitMillis;
  63 +
  64 + @Value("${redis.timeout}")
  65 + private long timeout;
  66 +
  67 + private Duration timeToLive = Duration.ofSeconds(600);
  68 +
  69 + /**
  70 + * 在没有指定缓存Key的情况下,key生成策略
  71 + */
  72 + @Bean
  73 + public KeyGenerator keyGenerator()
  74 + {
  75 + return new KeyGenerator()
  76 + {
  77 + @Override
  78 + public Object generate(Object target, Method method, Object... params)
  79 + {
  80 + StringBuffer sb = new StringBuffer();
  81 + sb.append(target.getClass().getName());
  82 + sb.append(method.getName());
  83 + for (Object obj : params)
  84 + {
  85 + sb.append(obj.toString());
  86 + }
  87 + return sb.toString();
  88 + }
  89 + };
  90 + }
  91 +
  92 + // 缓存管理器 使用Lettuce,和jedis有很大不同LettuceConnectionFactory lettuceConnectionFactory
  93 + @Bean
  94 + public CacheManager cacheManager()
  95 + {
  96 + // 关键点,spring cache的注解使用的序列化都从这来,没有这个配置的话使用的jdk自己的序列化,实际上不影响使用,只是打印出来不适合人眼识别
  97 + RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
  98 + .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))// key序列化方式
  99 + .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(getValueSerializer()))// value序列化方式
  100 + .disableCachingNullValues().entryTtl(timeToLive).disableCachingNullValues();
  101 + ;// 缓存过期时间
  102 +
  103 + RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.RedisCacheManagerBuilder
  104 + .fromConnectionFactory(lettuceConnectionFactory())// 默认有锁 等待锁时间为0
  105 + .cacheDefaults(redisCacheConfiguration).transactionAware();
  106 + return builder.build();
  107 + }
  108 +
  109 + /**
  110 + * RedisTemplate配置 使用自定义redisTemplate的时候 重新定义序列化方式 LettuceConnectionFactory lettuceConnectionFactory
  111 + */
  112 + @Bean
  113 + public RedisTemplate<String, Object> redisTemplate()
  114 + {
  115 + // 配置redisTemplate
  116 + RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
  117 + redisTemplate.setConnectionFactory(lettuceConnectionFactory());
  118 +
  119 + RedisSerializer<?> stringSerializer = new StringRedisSerializer();
  120 +
  121 + redisTemplate.setKeySerializer(stringSerializer);// key序列化
  122 + redisTemplate.setValueSerializer(getValueSerializer());// value序列化new LZ4Serializer(getValueSerializer())
  123 + redisTemplate.setHashKeySerializer(stringSerializer);// Hash key序列化
  124 + redisTemplate.setHashValueSerializer(getValueSerializer());// Hash value序列化
  125 + redisTemplate.afterPropertiesSet();
  126 +
  127 + return redisTemplate;
  128 + }
  129 +
  130 + /**
  131 + * shiroRedisTemplate配置 使用自定义shiroRedisTemplate的时候 重新定义序列化方式 LettuceConnectionFactory lettuceConnectionFactory
  132 + */
  133 + @Bean
  134 + public RedisTemplate<String, Object> shiroRedisTemplate()
  135 + {
  136 + // 配置redisTemplate
  137 + RedisTemplate<String, Object> shiroRedisTemplate = new RedisTemplate<String, Object>();
  138 + shiroRedisTemplate.setConnectionFactory(lettuceConnectionFactory());
  139 +
  140 + RedisSerializer<?> stringSerializer = new StringRedisSerializer();
  141 +
  142 + shiroRedisTemplate.setKeySerializer(stringSerializer);// key序列化
  143 + shiroRedisTemplate.setValueSerializer(new SerializeUtils<Object>());// value序列化
  144 + shiroRedisTemplate.setHashKeySerializer(stringSerializer);// Hash key序列化
  145 + shiroRedisTemplate.setHashValueSerializer(new SerializeUtils<Object>());// Hash value序列化
  146 + shiroRedisTemplate.afterPropertiesSet();
  147 +
  148 + return shiroRedisTemplate;
  149 + }
  150 +
  151 + private RedisSerializer<String> keySerializer()
  152 + {
  153 + return new StringRedisSerializer();
  154 + }
  155 +
  156 + private RedisSerializer<Object> getValueSerializer()
  157 + {
  158 + // 设置序列化
  159 + Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(
  160 + Object.class);
  161 + ObjectMapper om = new ObjectMapper();
  162 + om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
  163 + om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  164 + jackson2JsonRedisSerializer.setObjectMapper(om);
  165 + return jackson2JsonRedisSerializer;
  166 + }
  167 +
  168 + // 单机版配置连接参数
  169 + @Bean
  170 + public RedisStandaloneConfiguration redisStandaloneConfiguration()
  171 + {
  172 + RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
  173 + redisStandaloneConfiguration.setDatabase(database);
  174 + redisStandaloneConfiguration.setHostName(host);
  175 + redisStandaloneConfiguration.setPort(port);
  176 + redisStandaloneConfiguration.setPassword(RedisPassword.of(password));
  177 +
  178 + // 集群版配置
  179 + // RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
  180 + // String[] serverArray = clusterNodes.split(",");
  181 + // Set<RedisNode> nodes = new HashSet<RedisNode>();
  182 + // for (String ipPort : serverArray) {
  183 + // String[] ipAndPort = ipPort.split(":");
  184 + // nodes.add(new RedisNode(ipAndPort[0].trim(), Integer.valueOf(ipAndPort[1])));
  185 + // }
  186 + // redisClusterConfiguration.setPassword(RedisPassword.of(password));
  187 + // redisClusterConfiguration.setClusterNodes(nodes);
  188 + // redisClusterConfiguration.setMaxRedirects(maxRedirects);
  189 +
  190 + return redisStandaloneConfiguration;
  191 + }
  192 +
  193 + /**
  194 + * 配置LettuceClientConfiguration 包括线程池配置和安全项配置 genericObjectPoolConfig common-pool2线程池GenericObjectPoolConfig
  195 + * genericObjectPoolConfig
  196 + *
  197 + * @return lettuceClientConfiguration
  198 + */
  199 + @Bean
  200 + public LettuceClientConfiguration lettuceClientConfiguration()
  201 + {
  202 + LettuceClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder()
  203 + .commandTimeout(Duration.ofMillis(timeout)).shutdownTimeout(Duration.ofMillis(200))
  204 + .poolConfig(genericObjectPoolConfig()).build();
  205 + if (ssl)
  206 + {
  207 + lettuceClientConfiguration.isUseSsl();
  208 + }
  209 + return lettuceClientConfiguration;
  210 + }
  211 +
  212 + // 设置连接工厂
  213 + @Bean
  214 + public LettuceConnectionFactory lettuceConnectionFactory()
  215 + {
  216 + return new LettuceConnectionFactory(redisStandaloneConfiguration(), lettuceClientConfiguration());
  217 + }
  218 +
  219 + /**
  220 + * GenericObjectPoolConfig 连接池配置
  221 + */
  222 + @Bean
  223 + @ConfigurationProperties(prefix = "redis.lettuce.pool")
  224 + @Scope(value = "prototype")
  225 + @SuppressWarnings("rawtypes")
  226 + public GenericObjectPoolConfig genericObjectPoolConfig()
  227 + {
  228 + return new GenericObjectPoolConfig();
  229 + }
  230 +}
... ...
src/main/java/com/huaheng/framework/config/ShiroConfig.java
... ... @@ -12,6 +12,7 @@ import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
12 12 import org.apache.shiro.web.mgt.CookieRememberMeManager;
13 13 import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
14 14 import org.apache.shiro.web.servlet.SimpleCookie;
  15 +import org.springframework.beans.factory.annotation.Autowired;
15 16 import org.springframework.beans.factory.annotation.Qualifier;
16 17 import org.springframework.beans.factory.annotation.Value;
17 18 import org.springframework.context.annotation.Bean;
... ... @@ -36,11 +37,15 @@ import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
36 37 public class ShiroConfig {
37 38 public static final String PREMISSION_STRING = "perms[\"{0}\"]";
38 39  
39   - // Session超时时间,单位为毫秒(默认30分钟)
  40 + @Value("${shiro.session.redisEnabled}")
  41 + private boolean redisEnabled;
  42 +
  43 +
  44 + // Session超时时间,单位为毫秒
40 45 @Value("${shiro.session.expireTime}")
41 46 private int expireTime;
42 47  
43   - // 相隔多久检查一次session的有效性,单位毫秒,默认就是10分钟
  48 + // 相隔多久检查一次session的有效性,单位毫秒
44 49 @Value("${shiro.session.validationInterval}")
45 50 private int validationInterval;
46 51  
... ... @@ -80,29 +85,33 @@ public class ShiroConfig {
80 85 @Value("${shiro.user.unauthorizedUrl}")
81 86 private String unauthorizedUrl;
82 87  
  88 + @Autowired
  89 + private CacheManagerConfig cacheManagerConfig;
  90 +
83 91 /**
84 92 * 缓存管理器 使用Ehcache实现
85 93 */
86   - @Bean
87   - public EhCacheManager getEhCacheManager() {
88   - net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.getCacheManager("huaheng");
89   - EhCacheManager em = new EhCacheManager();
90   - if (StringUtils.isNull(cacheManager)) {
91   - em.setCacheManagerConfigFile("classpath:ehcache/ehcache-shiro.xml");
92   - return em;
93   - } else {
94   - em.setCacheManager(cacheManager);
95   - return em;
96   - }
97   - }
  94 + //@Bean
  95 + //public EhCacheManager getEhCacheManager() {
  96 + // net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.getCacheManager("huaheng");
  97 + // EhCacheManager em = new EhCacheManager();
  98 + // if (StringUtils.isNull(cacheManager)) {
  99 + // em.setCacheManagerConfigFile("classpath:ehcache/ehcache-shiro.xml");
  100 + // return em;
  101 + // } else {
  102 + // em.setCacheManager(cacheManager);
  103 + // return em;
  104 + // }
  105 + //}
98 106  
99 107 /**
100 108 * 自定义Realm
101 109 */
102 110 @Bean
103   - public UserRealm userRealm(EhCacheManager cacheManager) {
  111 + public UserRealm userRealm() {
104 112 UserRealm userRealm = new UserRealm();
105   - userRealm.setCacheManager(cacheManager);
  113 + userRealm.setCacheManager(
  114 + redisEnabled ? cacheManagerConfig.getRedisCacheManager() : cacheManagerConfig.getEhCacheManager());
106 115 return userRealm;
107 116 }
108 117  
... ... @@ -131,7 +140,7 @@ public class ShiroConfig {
131 140 public SpringSessionValidationScheduler sessionValidationScheduler() {
132 141 SpringSessionValidationScheduler sessionValidationScheduler = new SpringSessionValidationScheduler();
133 142 // 相隔多久检查一次session的有效性,单位毫秒,默认就是10分钟
134   - sessionValidationScheduler.setSessionValidationInterval(validationInterval * 60 * 1000);
  143 + sessionValidationScheduler.setSessionValidationInterval(validationInterval);
135 144 // 设置会话验证调度器进行会话验证时的会话管理器
136 145 sessionValidationScheduler.setSessionManager(sessionValidationManager());
137 146 return sessionValidationScheduler;
... ... @@ -144,11 +153,11 @@ public class ShiroConfig {
144 153 public OnlineWebSessionManager sessionValidationManager() {
145 154 OnlineWebSessionManager manager = new OnlineWebSessionManager();
146 155 // 加入缓存管理器
147   - manager.setCacheManager(getEhCacheManager());
  156 + manager.setCacheManager(redisEnabled ? cacheManagerConfig.getRedisCacheManager() : cacheManagerConfig.getEhCacheManager());
148 157 // 删除过期的session
149 158 manager.setDeleteInvalidSessions(true);
150 159 // 设置全局session超时时间
151   - manager.setGlobalSessionTimeout(expireTime * 60 * 1000);
  160 + manager.setGlobalSessionTimeout(expireTime);
152 161 // 去掉 JSESSIONID
153 162 manager.setSessionIdUrlRewritingEnabled(false);
154 163 // 是否定时检查session
... ... @@ -167,11 +176,11 @@ public class ShiroConfig {
167 176 public OnlineWebSessionManager sessionManager() {
168 177 OnlineWebSessionManager manager = new OnlineWebSessionManager();
169 178 // 加入缓存管理器
170   - manager.setCacheManager(getEhCacheManager());
  179 + manager.setCacheManager(redisEnabled ? cacheManagerConfig.getRedisCacheManager() : cacheManagerConfig.getEhCacheManager());
171 180 // 删除过期的session
172 181 manager.setDeleteInvalidSessions(true);
173 182 // 设置全局session超时时间
174   - manager.setGlobalSessionTimeout(expireTime * 60 * 1000);
  183 + manager.setGlobalSessionTimeout(expireTime);
175 184 // 去掉 JSESSIONID
176 185 manager.setSessionIdUrlRewritingEnabled(false);
177 186 // 定义要使用的无效的Session定时调度器
... ... @@ -196,7 +205,9 @@ public class ShiroConfig {
196 205 // 记住我
197 206 securityManager.setRememberMeManager(rememberMeManager());
198 207 // 注入缓存管理器;
199   - securityManager.setCacheManager(getEhCacheManager());
  208 + securityManager.setCacheManager(
  209 + redisEnabled ? cacheManagerConfig.getRedisCacheManager() : cacheManagerConfig.getEhCacheManager());
  210 +
200 211 // session管理器
201 212 securityManager.setSessionManager(sessionManager());
202 213 return securityManager;
... ... @@ -288,7 +299,7 @@ public class ShiroConfig {
288 299 //filterChainDefinitionMap.put("/mobile/inventory/completeTaskListByWMS", "anon");
289 300 //filterChainDefinitionMap.put("/receipt/receiving/saveBatch", "anon");
290 301 //filterChainDefinitionMap.put("/config/zone/getAllFlatLocation", "anon");
291   - filterChainDefinitionMap.put("/mobile/getModules2", "anon");
  302 + //filterChainDefinitionMap.put("/mobile/getModules2", "anon");
292 303  
293 304  
294 305 // 系统权限列表
... ... @@ -337,7 +348,7 @@ public class ShiroConfig {
337 348 cookie.setDomain(domain);
338 349 cookie.setPath(path);
339 350 cookie.setHttpOnly(httpOnly);
340   - cookie.setMaxAge(maxAge * 24 * 60 * 1000);
  351 + cookie.setMaxAge(maxAge * 24 * 60 * 60);
341 352 return cookie;
342 353 }
343 354  
... ...
src/main/java/com/huaheng/framework/redis/Exception/CacheManagerPrincipalIdNotAssignedException.java 0 → 100644
  1 +package com.huaheng.framework.redis.Exception;
  2 +
  3 +@SuppressWarnings("serial")
  4 +public class CacheManagerPrincipalIdNotAssignedException extends RuntimeException
  5 +{
  6 + private static final String MESSAGE = "CacheManager didn't assign Principal Id field name!";
  7 +
  8 + public CacheManagerPrincipalIdNotAssignedException()
  9 + {
  10 + super(MESSAGE);
  11 + }
  12 +}
... ...
src/main/java/com/huaheng/framework/redis/Exception/PrincipalIdNullException.java 0 → 100644
  1 +package com.huaheng.framework.redis.Exception;
  2 +
  3 +@SuppressWarnings("serial")
  4 +public class PrincipalIdNullException extends RuntimeException
  5 +{
  6 + private static final String MESSAGE = "Principal Id shouldn't be null!";
  7 +
  8 + @SuppressWarnings("rawtypes")
  9 + public PrincipalIdNullException(Class clazz, String idMethodName)
  10 + {
  11 + super(clazz + " id field: " + idMethodName + ", value is null\n" + MESSAGE);
  12 + }
  13 +}
... ...
src/main/java/com/huaheng/framework/redis/Exception/PrincipalInstanceException.java 0 → 100644
  1 +package com.huaheng.framework.redis.Exception;
  2 +
  3 +@SuppressWarnings("serial")
  4 +public class PrincipalInstanceException extends RuntimeException
  5 +{
  6 + private static final String MESSAGE = "We need a field to identify this Cache Object in Redis. "
  7 + + "So you need to defined an id field which you can get unique id to identify this principal. "
  8 + + "For example, if you use UserInfo as Principal class, the id field maybe userId, userName, email, etc. "
  9 + + "For example, getUserId(), getUserName(), getEmail(), etc.\n"
  10 + + "Default value is authCacheKey or id, that means your principal object has a method called \"getAuthCacheKey()\" or \"getId()\"";
  11 +
  12 + @SuppressWarnings("rawtypes")
  13 + public PrincipalInstanceException(Class clazz, String idMethodName)
  14 + {
  15 + super(clazz + " must has getter for field: " + idMethodName + "\n" + MESSAGE);
  16 + }
  17 +
  18 + @SuppressWarnings("rawtypes")
  19 + public PrincipalInstanceException(Class clazz, String idMethodName, Exception e)
  20 + {
  21 + super(clazz + " must has getter for field: " + idMethodName + "\n" + MESSAGE, e);
  22 + }
  23 +}
... ...
src/main/java/com/huaheng/framework/redis/RedisCacheManager.java 0 → 100644
  1 +package com.huaheng.framework.redis;
  2 +
  3 +import com.huaheng.common.utils.RedisUtils;
  4 +import org.apache.shiro.cache.Cache;
  5 +import org.apache.shiro.cache.CacheException;
  6 +import org.apache.shiro.cache.CacheManager;
  7 +import org.slf4j.Logger;
  8 +import org.slf4j.LoggerFactory;
  9 +import org.springframework.beans.factory.annotation.Autowired;
  10 +import org.springframework.beans.factory.annotation.Value;
  11 +import org.springframework.stereotype.Component;
  12 +
  13 +import java.util.concurrent.ConcurrentHashMap;
  14 +import java.util.concurrent.ConcurrentMap;
  15 +
  16 +@Component
  17 +public class RedisCacheManager implements CacheManager
  18 +{
  19 + private final Logger logger = LoggerFactory.getLogger(RedisCacheManager.class);
  20 +
  21 + @SuppressWarnings({ "unchecked", "rawtypes" })
  22 + private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap();
  23 +
  24 + @Autowired
  25 + private RedisUtils redisUtils;
  26 +
  27 + public static final String DEFAULT_CACHE_KEY_PREFIX = "shiro:redisCache:";
  28 + private String keyPrefix = DEFAULT_CACHE_KEY_PREFIX;
  29 +
  30 + // expire time in seconds
  31 + public static final long DEFAULT_EXPIRE = 30 * 60 * 1000;
  32 + @Value("${redis.timeout}")
  33 + private long expire ;
  34 +
  35 + public static final String DEFAULT_PRINCIPAL_ID_FIELD_NAME = "authCacheKey or id";
  36 + private String principalIdFieldName = DEFAULT_PRINCIPAL_ID_FIELD_NAME;
  37 +
  38 + @SuppressWarnings({ "rawtypes", "unchecked" })
  39 + @Override
  40 + public <K, V> Cache<K, V> getCache(String cacheName) throws CacheException
  41 + {
  42 + this.logger.debug("get cache, cacheName=" + cacheName);
  43 + Cache cache = (Cache) this.caches.get(cacheName);
  44 + if (cache == null)
  45 + {
  46 + this.logger.debug("get cache but cache is null");
  47 + cache = new ShiroRedisCache(this.redisUtils, this.keyPrefix + cacheName + ":", expire,
  48 + this.principalIdFieldName);
  49 + this.caches.put(cacheName, cache);
  50 + }
  51 +
  52 + return (Cache) cache;
  53 + }
  54 +
  55 + public String getKeyPrefix()
  56 + {
  57 + return keyPrefix;
  58 + }
  59 +
  60 + public void setKeyPrefix(String keyPrefix)
  61 + {
  62 + this.keyPrefix = keyPrefix;
  63 + }
  64 +
  65 + public long getExpire()
  66 + {
  67 + return expire;
  68 + }
  69 +
  70 + public void setExpire(long expire)
  71 + {
  72 + this.expire = expire;
  73 + }
  74 +
  75 + public String getPrincipalIdFieldName()
  76 + {
  77 + return principalIdFieldName;
  78 + }
  79 +
  80 + public void setPrincipalIdFieldName(String principalIdFieldName)
  81 + {
  82 + this.principalIdFieldName = principalIdFieldName;
  83 + }
  84 +
  85 + public void setRedisUtils(RedisUtils redisUtils)
  86 + {
  87 + this.redisUtils = redisUtils;
  88 + }
  89 +}
... ...
src/main/java/com/huaheng/framework/redis/ShiroRedisCache.java 0 → 100644
  1 +package com.huaheng.framework.redis;
  2 +
  3 +import com.huaheng.common.utils.RedisUtils;
  4 +import com.huaheng.framework.redis.Exception.CacheManagerPrincipalIdNotAssignedException;
  5 +import com.huaheng.framework.redis.Exception.PrincipalIdNullException;
  6 +import com.huaheng.framework.redis.Exception.PrincipalInstanceException;
  7 +import org.apache.shiro.cache.Cache;
  8 +import org.apache.shiro.cache.CacheException;
  9 +import org.apache.shiro.subject.PrincipalCollection;
  10 +import org.apache.shiro.util.CollectionUtils;
  11 +import org.slf4j.Logger;
  12 +import org.slf4j.LoggerFactory;
  13 +import org.springframework.data.redis.serializer.SerializationException;
  14 +
  15 +import java.lang.reflect.InvocationTargetException;
  16 +import java.lang.reflect.Method;
  17 +import java.util.*;
  18 +
  19 +public class ShiroRedisCache<K, V> implements Cache<K, V>
  20 +{
  21 + private final Logger logger = LoggerFactory.getLogger(ShiroRedisCache.class);
  22 +
  23 + private RedisUtils redisUtils;
  24 +
  25 + private String keyPrefix = RedisCacheManager.DEFAULT_CACHE_KEY_PREFIX;
  26 +
  27 + private long expire = RedisCacheManager.DEFAULT_EXPIRE;
  28 +
  29 + private String principalIdFieldName = RedisCacheManager.DEFAULT_PRINCIPAL_ID_FIELD_NAME;
  30 +
  31 + public ShiroRedisCache(RedisUtils redisUtils, String prefix, long expire, String principalIdFieldName)
  32 + {
  33 + if (redisUtils == null)
  34 + {
  35 + throw new IllegalArgumentException("redisUtils cannot be null.");
  36 + }
  37 + this.redisUtils = redisUtils;
  38 + if (prefix != null && !"".equals(prefix))
  39 + {
  40 + this.keyPrefix = prefix;
  41 + }
  42 + if (expire != -1)
  43 + {
  44 + this.expire = expire;
  45 + }
  46 + if (principalIdFieldName != null && !"".equals(principalIdFieldName))
  47 + {
  48 + this.principalIdFieldName = principalIdFieldName;
  49 + }
  50 + }
  51 +
  52 + @SuppressWarnings("unchecked")
  53 + @Override
  54 + public V get(K key) throws CacheException
  55 + {
  56 + if (key == null)
  57 + {
  58 + return null;
  59 + }
  60 + else
  61 + {
  62 +
  63 + String redisCacheKey = getRedisCacheKey(key);
  64 + Object rawValue = redisUtils.get(true, redisCacheKey);
  65 +
  66 + if (rawValue == null)
  67 + {
  68 + return null;
  69 + }
  70 + V value = (V) rawValue;
  71 + return value;
  72 + }
  73 +
  74 + }
  75 +
  76 + @Override
  77 + public V put(K key, V value) throws CacheException
  78 + {
  79 + if (key == null)
  80 + {
  81 + logger.warn("Saving a null key is meaningless, return value directly without call Redis.");
  82 + return value;
  83 + }
  84 + try
  85 + {
  86 + String redisCacheKey = getRedisCacheKey(key);
  87 + redisUtils.set(true, redisCacheKey, value != null ? value : null, expire);
  88 + return value;
  89 + }
  90 + catch (SerializationException e)
  91 + {
  92 + throw new CacheException(e);
  93 + }
  94 + }
  95 +
  96 + private String getRedisCacheKey(K key)
  97 + {
  98 + if (key == null)
  99 + {
  100 + return null;
  101 + }
  102 +
  103 + return this.keyPrefix + getStringRedisKey(key);
  104 +
  105 + }
  106 +
  107 + private String getStringRedisKey(K key)
  108 + {
  109 + String redisKey;
  110 + if (key instanceof PrincipalCollection)
  111 + {
  112 + redisKey = getRedisKeyFromPrincipalIdField((PrincipalCollection) key);
  113 + }
  114 + else
  115 + {
  116 + redisKey = key.toString();
  117 + }
  118 + return redisKey;
  119 + }
  120 +
  121 + /**
  122 + * getRedisKeyFromPrincipalIdField()是获取缓存的用户身份信息 和用户权限信息。 里面有一个属性principalIdFieldName
  123 + * 在RedisCacheManager也有这个属性,设置其中一个就可以.是为了给缓存用户身份和权限信息在Redis中的key唯一, 登录用户名可能是username 或者 phoneNum 或者是Email中的一个, 如
  124 + * 我的User实体类中 有一个 usernane字段,也是登录时候使用的用户名,在redis中缓存的权限信息key 如下, 这个admin 就是 通过getUsername获得的。
  125 + */
  126 +
  127 + private String getRedisKeyFromPrincipalIdField(PrincipalCollection key)
  128 + {
  129 + Object principalObject = key.getPrimaryPrincipal();
  130 + if (principalObject instanceof String)
  131 + {
  132 + return principalObject.toString();
  133 + }
  134 + Method pincipalIdGetter = getPrincipalIdGetter(principalObject);
  135 + return getIdObj(principalObject, pincipalIdGetter);
  136 + }
  137 +
  138 + private String getIdObj(Object principalObject, Method pincipalIdGetter)
  139 + {
  140 + String redisKey;
  141 + try
  142 + {
  143 + Object idObj = pincipalIdGetter.invoke(principalObject);
  144 + if (idObj == null)
  145 + {
  146 + throw new PrincipalIdNullException(principalObject.getClass(), this.principalIdFieldName);
  147 + }
  148 + redisKey = idObj.toString();
  149 + }
  150 + catch (IllegalAccessException e)
  151 + {
  152 + throw new PrincipalInstanceException(principalObject.getClass(), this.principalIdFieldName, e);
  153 + }
  154 + catch (InvocationTargetException e)
  155 + {
  156 + throw new PrincipalInstanceException(principalObject.getClass(), this.principalIdFieldName, e);
  157 + }
  158 + return redisKey;
  159 + }
  160 +
  161 + private Method getPrincipalIdGetter(Object principalObject)
  162 + {
  163 + Method pincipalIdGetter = null;
  164 + String principalIdMethodName = this.getPrincipalIdMethodName();
  165 + try
  166 + {
  167 + pincipalIdGetter = principalObject.getClass().getMethod(principalIdMethodName);
  168 + }
  169 + catch (NoSuchMethodException e)
  170 + {
  171 + throw new PrincipalInstanceException(principalObject.getClass(), this.principalIdFieldName);
  172 + }
  173 + return pincipalIdGetter;
  174 + }
  175 +
  176 + private String getPrincipalIdMethodName()
  177 + {
  178 + if (this.principalIdFieldName == null || "".equals(this.principalIdFieldName))
  179 + {
  180 + throw new CacheManagerPrincipalIdNotAssignedException();
  181 + }
  182 + return "get" + this.principalIdFieldName.substring(0, 1).toUpperCase() + this.principalIdFieldName.substring(1);
  183 + }
  184 +
  185 + @SuppressWarnings("unchecked")
  186 + @Override
  187 + public V remove(K key) throws CacheException
  188 + {
  189 + if (key == null)
  190 + {
  191 + return null;
  192 + }
  193 + try
  194 + {
  195 + String redisCacheKey = getRedisCacheKey(key);
  196 + Object rawValue = redisUtils.get(true, redisCacheKey);
  197 + V previous = (V) rawValue;
  198 + redisUtils.del(true, redisCacheKey);
  199 + return previous;
  200 + }
  201 + catch (SerializationException e)
  202 + {
  203 + throw new CacheException(e);
  204 + }
  205 + }
  206 +
  207 + @Override
  208 + public void clear() throws CacheException
  209 + {
  210 + Set<String> keys = null;
  211 + try
  212 + {
  213 + keys = redisUtils.scan(true, this.keyPrefix + "*");
  214 + }
  215 + catch (SerializationException e)
  216 + {
  217 + logger.error("get keys error", e);
  218 + }
  219 + if (keys == null || keys.size() == 0)
  220 + {
  221 + return;
  222 + }
  223 + for (String key : keys)
  224 + {
  225 + redisUtils.del(true, key);
  226 + }
  227 + }
  228 +
  229 + @Override
  230 + public int size()
  231 + {
  232 + Long longSize = 0L;
  233 + try
  234 + {
  235 + longSize = new Long(redisUtils.scanSize(true, this.keyPrefix + "*"));
  236 + }
  237 + catch (SerializationException e)
  238 + {
  239 + logger.error("get keys error", e);
  240 + }
  241 + return longSize.intValue();
  242 + }
  243 +
  244 + @SuppressWarnings("unchecked")
  245 + @Override
  246 + public Set<K> keys()
  247 + {
  248 + Set<String> keys = null;
  249 + try
  250 + {
  251 + keys = redisUtils.scan(true, this.keyPrefix + "*");
  252 + }
  253 + catch (SerializationException e)
  254 + {
  255 + logger.error("get keys error", e);
  256 + return Collections.emptySet();
  257 + }
  258 +
  259 + if (CollectionUtils.isEmpty(keys))
  260 + {
  261 + return Collections.emptySet();
  262 + }
  263 +
  264 + Set<K> convertedKeys = new HashSet<K>();
  265 + for (String key : keys)
  266 + {
  267 + try
  268 + {
  269 + convertedKeys.add((K) key);
  270 + }
  271 + catch (SerializationException e)
  272 + {
  273 + logger.error("deserialize keys error", e);
  274 + }
  275 + }
  276 + return convertedKeys;
  277 + }
  278 +
  279 + @SuppressWarnings("unchecked")
  280 + @Override
  281 + public Collection<V> values()
  282 + {
  283 + Set<String> keys = null;
  284 + try
  285 + {
  286 + keys = redisUtils.scan(true, this.keyPrefix + "*");
  287 + }
  288 + catch (SerializationException e)
  289 + {
  290 + logger.error("get values error", e);
  291 + return Collections.emptySet();
  292 + }
  293 +
  294 + if (CollectionUtils.isEmpty(keys))
  295 + {
  296 + return Collections.emptySet();
  297 + }
  298 +
  299 + List<V> values = new ArrayList<V>(keys.size());
  300 + for (String key : keys)
  301 + {
  302 + V value = null;
  303 + try
  304 + {
  305 + value = (V) redisUtils.get(true, key);
  306 + }
  307 + catch (SerializationException e)
  308 + {
  309 + logger.error("deserialize values= error", e);
  310 + }
  311 + if (value != null)
  312 + {
  313 + values.add(value);
  314 + }
  315 + }
  316 + return Collections.unmodifiableList(values);
  317 + }
  318 +
  319 + public String getKeyPrefix()
  320 + {
  321 + return keyPrefix;
  322 + }
  323 +
  324 + public void setKeyPrefix(String keyPrefix)
  325 + {
  326 + this.keyPrefix = keyPrefix;
  327 + }
  328 +
  329 + public long getExpire()
  330 + {
  331 + return expire;
  332 + }
  333 +
  334 + public void setExpire(long expire)
  335 + {
  336 + this.expire = expire;
  337 + }
  338 +
  339 + public String getPrincipalIdFieldName()
  340 + {
  341 + return principalIdFieldName;
  342 + }
  343 +
  344 + public void setPrincipalIdFieldName(String principalIdFieldName)
  345 + {
  346 + this.principalIdFieldName = principalIdFieldName;
  347 + }
  348 +
  349 + public void setRedisUtils(RedisUtils redisUtils)
  350 + {
  351 + this.redisUtils = redisUtils;
  352 + }
  353 +}
... ...
src/main/java/com/huaheng/framework/redis/serializer/SerializeUtils.java 0 → 100644
  1 +package com.huaheng.framework.redis.serializer;
  2 +
  3 +import org.slf4j.Logger;
  4 +import org.slf4j.LoggerFactory;
  5 +import org.springframework.data.redis.serializer.RedisSerializer;
  6 +import org.springframework.data.redis.serializer.SerializationException;
  7 +
  8 +import java.io.*;
  9 +
  10 +public class SerializeUtils<T> implements RedisSerializer<T>
  11 +{
  12 + private static Logger logger = LoggerFactory.getLogger(SerializeUtils.class);
  13 +
  14 + public static boolean isEmpty(byte[] data)
  15 + {
  16 + return (data == null || data.length == 0);
  17 + }
  18 +
  19 + /**
  20 + * 序列化
  21 + *
  22 + * @param t
  23 + * @return
  24 + * @throws SerializationException
  25 + */
  26 + @Override
  27 + public byte[] serialize(T t) throws SerializationException
  28 + {
  29 + byte[] result = null;
  30 +
  31 + if (t == null)
  32 + {
  33 + return new byte[0];
  34 + }
  35 + try (ByteArrayOutputStream byteStream = new ByteArrayOutputStream(128);
  36 + ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteStream))
  37 + {
  38 +
  39 + if (!(t instanceof Serializable))
  40 + {
  41 + throw new IllegalArgumentException(
  42 + SerializeUtils.class.getSimpleName() + " requires a Serializable payload "
  43 + + "but received an object of type [" + t.getClass().getName() + "]");
  44 + }
  45 +
  46 + objectOutputStream.writeObject(t);
  47 + objectOutputStream.flush();
  48 + result = byteStream.toByteArray();
  49 + }
  50 + catch (Exception ex)
  51 + {
  52 + logger.error("Failed to serialize", ex);
  53 + }
  54 + return result;
  55 + }
  56 +
  57 + /**
  58 + * 反序列化
  59 + *
  60 + * @param bytes
  61 + * @return
  62 + * @throws SerializationException
  63 + */
  64 + @SuppressWarnings("unchecked")
  65 + @Override
  66 + public T deserialize(byte[] bytes) throws SerializationException
  67 + {
  68 + T result = null;
  69 + if (isEmpty(bytes))
  70 + {
  71 + return null;
  72 + }
  73 + ObjectInputStream objectInputStream;
  74 + try
  75 + {
  76 + objectInputStream = new ObjectInputStream(new ByteArrayInputStream(bytes));
  77 + result = (T) objectInputStream.readObject();
  78 + }
  79 + catch (Exception e)
  80 + {
  81 + logger.error("Failed to deserialize", e);
  82 + }
  83 + return result;
  84 + }
  85 +}
... ...
src/main/java/com/huaheng/framework/shiro/service/PasswordService.java
... ... @@ -2,6 +2,9 @@ package com.huaheng.framework.shiro.service;
2 2  
3 3 import java.util.concurrent.atomic.AtomicInteger;
4 4 import javax.annotation.PostConstruct;
  5 +
  6 +import com.huaheng.common.exception.user.UserPasswordRetryLimitCountException;
  7 +import com.huaheng.common.utils.RedisUtils;
5 8 import org.apache.shiro.cache.Cache;
6 9 import org.apache.shiro.cache.CacheManager;
7 10 import org.apache.shiro.crypto.hash.Md5Hash;
... ... @@ -17,74 +20,65 @@ import com.huaheng.pc.system.user.domain.User;
17 20  
18 21 /**
19 22 * 登录密码方法
20   - *
  23 + *
21 24 * @author huaheng
22 25 */
23 26 @Component
24   -public class PasswordService
25   -{
  27 +public class PasswordService {
26 28  
27 29 @Autowired
28   - private CacheManager cacheManager;
  30 + private RedisUtils redisManager;
29 31  
30 32 private Cache<String, AtomicInteger> loginRecordCache;
31 33  
32 34 @Value(value = "${user.password.maxRetryCount}")
33 35 private String maxRetryCount;
34 36  
35   - @PostConstruct
36   - public void init()
37   - {
38   - loginRecordCache = cacheManager.getCache("loginRecordCache");
  37 + public static final String DEFAULT_RETRYLIMIT_KEY_PREFIX = "shiro:redisCache:retry:limit:";
  38 + private String keyPrefix = DEFAULT_RETRYLIMIT_KEY_PREFIX;
  39 +
  40 + private String getRedisRetryLimitKey(String username) {
  41 + return this.keyPrefix + username;
39 42 }
40 43  
41   - public void validate(User user, String password)
42   - {
  44 + public void validate(User user, String password) {
43 45 String loginName = user.getLoginName();
44 46  
45   - AtomicInteger retryCount = loginRecordCache.get(loginName);
  47 + AtomicInteger retryCount = (AtomicInteger) redisManager.get(true, getRedisRetryLimitKey(loginName));
46 48  
47   - if (retryCount == null)
48   - {
  49 + if (retryCount == null) {
49 50 retryCount = new AtomicInteger(0);
50   - loginRecordCache.put(loginName, retryCount);
  51 + redisManager.set(true, getRedisRetryLimitKey(loginName), retryCount);
51 52 }
52   - if (retryCount.incrementAndGet() > Integer.valueOf(maxRetryCount).intValue())
53   - {
  53 + if (retryCount.incrementAndGet() > Integer.valueOf(maxRetryCount).intValue()) {
54 54 SystemLogUtils.log(loginName, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.exceed", maxRetryCount));
  55 + redisManager.set(true, getRedisRetryLimitKey(loginName), retryCount, 1 * 60 * 1000);
55 56 throw new UserPasswordRetryLimitExceedException(Integer.valueOf(maxRetryCount).intValue());
56 57 }
57 58  
58   - if (!matches(user, password))
59   - {
  59 + if (!matches(user, password)) {
60 60 SystemLogUtils.log(loginName, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.count", retryCount, password));
61   - loginRecordCache.put(loginName, retryCount);
62   - throw new UserPasswordNotMatchException();
63   - }
64   - else
65   - {
  61 + redisManager.set(true, getRedisRetryLimitKey(loginName), retryCount);
  62 + throw new UserPasswordRetryLimitCountException(Integer.valueOf(retryCount.incrementAndGet() - 1).intValue());
  63 + } else {
66 64 clearLoginRecordCache(loginName);
67 65 }
68 66 }
69 67  
70   - public boolean matches(User user, String newPassword)
71   - {
  68 + public boolean matches(User user, String newPassword) {
72 69 return user.getPassword().equals(encryptPassword(user.getLoginName(), newPassword, user.getSalt()));
73 70 }
74 71  
75   - public void clearLoginRecordCache(String username)
76   - {
77   - loginRecordCache.remove(username);
  72 + public void clearLoginRecordCache(String username) {
  73 + redisManager.del(true, getRedisRetryLimitKey(username));
78 74 }
79 75  
80   - public String encryptPassword(String username, String password, String salt)
81   - {
  76 + public String encryptPassword(String username, String password, String salt) {
82 77 return new Md5Hash(username + password + salt).toHex().toString();
83 78 }
84 79  
85   - public static void main(String[] args)
86   - {
87   - //System.out.println(new PasswordService().encryptPassword("admin", "admin123", "111111"));
  80 + public static void main(String[] args) {
  81 + System.out.println(new PasswordService().encryptPassword("huaheng", "123456", "c97f29"));
88 82 //System.out.println(new PasswordService().encryptPassword("ry", "admin123", "222222"));
89 83 }
90 84 }
... ...
src/main/java/com/huaheng/framework/shiro/web/filter/online/OnlineSessionFilter.java
... ... @@ -3,6 +3,9 @@ package com.huaheng.framework.shiro.web.filter.online;
3 3 import java.io.IOException;
4 4 import javax.servlet.ServletRequest;
5 5 import javax.servlet.ServletResponse;
  6 +
  7 +import com.huaheng.pc.system.dept.domain.Dept;
  8 +import com.huaheng.pc.system.dept.service.IDeptService;
6 9 import org.apache.shiro.session.Session;
7 10 import org.apache.shiro.subject.Subject;
8 11 import org.apache.shiro.web.filter.AccessControlFilter;
... ... @@ -17,11 +20,10 @@ import com.huaheng.pc.system.user.domain.User;
17 20  
18 21 /**
19 22 * 自定义访问控制
20   - *
  23 + *
21 24 * @author huaheng
22 25 */
23   -public class OnlineSessionFilter extends AccessControlFilter
24   -{
  26 +public class OnlineSessionFilter extends AccessControlFilter {
25 27  
26 28 /**
27 29 * 强制退出后重定向的地址
... ... @@ -32,39 +34,38 @@ public class OnlineSessionFilter extends AccessControlFilter
32 34 @Autowired
33 35 private OnlineSessionDAO onlineSessionDAO;
34 36  
  37 + @Autowired
  38 + private IDeptService deptService;
  39 +
35 40 /**
36 41 * 表示是否允许访问;mappedValue就是[urls]配置中拦截器参数部分,如果允许访问返回true,否则false;
37 42 */
38 43 @Override
39 44 protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
40   - throws Exception
41   - {
  45 + throws Exception {
42 46 Subject subject = getSubject(request, response);
43   - if (subject == null || subject.getSession() == null)
44   - {
  47 + if (subject == null || subject.getSession() == null) {
45 48 return true;
46 49 }
47 50 Session session = onlineSessionDAO.readSession(subject.getSession().getId());
48   - if (session != null && session instanceof OnlineSession)
49   - {
  51 + if (session != null && session instanceof OnlineSession) {
50 52 OnlineSession onlineSession = (OnlineSession) session;
51 53 request.setAttribute(ShiroConstants.ONLINE_SESSION, onlineSession);
52 54 // 把user对象设置进去
53 55 boolean isGuest = onlineSession.getUserId() == null || onlineSession.getUserId() == 0L;
54   - if (isGuest == true)
55   - {
  56 + if (isGuest == true) {
56 57 User user = ShiroUtils.getUser();
57   - if (user != null)
58   - {
  58 + if (user != null) {
  59 + Integer deptId = user.getDeptId();
  60 + Dept dept = deptService.selectDeptById(deptId);
59 61 onlineSession.setUserId(user.getId());
60 62 onlineSession.setLoginName(user.getLoginName());
61   - onlineSession.setDeptName(user.getDept().getDeptName());
  63 + onlineSession.setDeptName(dept.getDeptName());
62 64 onlineSession.markAttributeChanged();
63 65 }
64 66 }
65 67  
66   - if (onlineSession.getStatus() == OnlineSession.OnlineStatus.off_line)
67   - {
  68 + if (onlineSession.getStatus() == OnlineSession.OnlineStatus.off_line) {
68 69 return false;
69 70 }
70 71 }
... ... @@ -75,11 +76,9 @@ public class OnlineSessionFilter extends AccessControlFilter
75 76 * 表示当访问拒绝时是否已经处理了;如果返回true表示需要继续处理;如果返回false表示该拦截器实例已经处理了,将直接返回即可。
76 77 */
77 78 @Override
78   - protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception
79   - {
  79 + protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
80 80 Subject subject = getSubject(request, response);
81   - if (subject != null)
82   - {
  81 + if (subject != null) {
83 82 subject.logout();
84 83 }
85 84 saveRequestAndRedirectToLogin(request, response);
... ... @@ -88,8 +87,7 @@ public class OnlineSessionFilter extends AccessControlFilter
88 87  
89 88 // 跳转到登录页
90 89 @Override
91   - protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException
92   - {
  90 + protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
93 91 WebUtils.issueRedirect(request, response, loginUrl);
94 92 }
95 93  
... ...
src/main/resources/application.yml
... ... @@ -9,7 +9,7 @@ huaheng:
9 9 #版本
10 10 version: 4.0.0
11 11 #版权年份
12   - copyrightYear: 2022
  12 + copyrightYear: 2024
13 13 # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
14 14 profile: D:/Huaheng/uploadPath/
15 15 # apk路径
... ... @@ -106,29 +106,27 @@ spring:
106 106 password: owobzjvlgsxrbdfe
107 107 # 编码类型
108 108 default-encoding: utf-8
109   - # redis 配置
110   - redis:
111   - # 地址
112   - # host: 192.168.100.132
113   - # host: 192.168.100.134
114   - # host: 192.168.100.136
115   - host: localhost
116   - # 端口,默认为6379
117   - port: 6379
118   - # 密码
119   - password:
120   - # 连接超时时间
121   - timeout: 10s
122   - lettuce:
123   - pool:
124   - # 连接池中的最小空闲连接
125   - min-idle: 0
126   - # 连接池中的最大空闲连接
127   - max-idle: 8
128   - # 连接池的最大数据库连接数
129   - max-active: 8
130   - # #连接池最大阻塞等待时间(使用负值表示没有限制)
131   - max-wait: -1ms
  109 +
  110 +
  111 +
  112 +# redis 配置
  113 +redis:
  114 + database: 0
  115 + host: localhost
  116 + lettuce:
  117 + pool:
  118 + max-active: 8 #最大连接数据库连接数,设 0 为没有限制
  119 + max-idle: 8 #最大等待连接中的数量,设 0 为没有限制
  120 + max-wait: -1ms #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
  121 + min-idle: 0 #最小等待连接中的数量,设 0 为没有限制
  122 + max-total: 50 #连接池最大连接数(使用负值表示没有限制)
  123 + max-waitMillis: -1 #连接池最大阻塞等待时间(使用负值表示没有限制)
  124 + shutdown-timeout: 100ms
  125 + password:
  126 + #password:
  127 + port: 6379
  128 + ssl: true
  129 + timeout: 14400000 #4h 4*60*60*1000
132 130  
133 131 mybatis-plus:
134 132 mapper-locations: classpath:mybatis/**/*.xml
... ... @@ -168,12 +166,14 @@ shiro:
168 166 # 设置Cookie的过期时间,天为单位
169 167 maxAge: -1
170 168 session:
  169 + #启用redisCache
  170 + redisEnabled: true
171 171 # Session超时时间(默认30分钟)
172 172 expireTime: -1
173 173 # 同步session到数据库的周期(默认1分钟)
174 174 dbSyncPeriod: 1
175 175 # 相隔多久检查一次session的有效性,默认就是10分钟
176   - validationInterval: -1
  176 + validationInterval: 1000000
177 177  
178 178 # 防止XSS攻击
179 179 xss:
... ...