This commit is contained in:
ouburikou
2018-02-08 16:45:14 +08:00
parent bb00973025
commit 91ab2ed237
28 changed files with 463 additions and 362 deletions

0
dem Normal file
View File

View File

@@ -7,9 +7,7 @@ import java.util.Map;
public class Constants {
/**
* 企业用户需要审核才能登陆,非企业用户默认审核成功
*/
public static String userStatus_0="0";//注册用户未审核
public static String userStatus_1="1";//注册用户已审核
public static String userStatus_2="2";//注册用户被锁定
@@ -33,64 +31,6 @@ public class Constants {
/*****************************************shiro redis 管理设置 end*********************************************************/
/*****************************************报表导出 start*********************************************************/
public static List<String> list1 =new ArrayList<String>();
public static List<String> list2 =new ArrayList<String>();
public static Map<String, List> map=new HashMap<String, List>();
public static Map<String, String> mapValue=new HashMap<String, String>();
static{
list1.add("与工业控制系统网络相连的网络");
list1.add("连接方式");
list1.add("连接时间");
list1.add("连接后身份认证方式");
list1.add("连接管理制度");
list1.add("合法系统间互联的识别和认证技术措施");
list2.add("移动存储介质使用管理制度");
list2.add("系统网络和公共网之间交叉使用移动存储介质");
list2.add("工业控制系统主机的存储介质使用情况检查");
list2.add("移动存储介质自动播放功能");
list2.add("工业控制系统与其他系统之间专用的安全信息交换途径");
list2.add("移动存储介质销毁处置流程");
map.put("工业控制系统网络与公共网络的连接管理",list1);
map.put("存储介质使用管理",list2);
mapValue.put("与工业控制系统网络相连的网络", "内部局域网-互联网-企业管理网-其他网络-无连接");
mapValue.put("连接方式","直接相连-采取隔离措施后连接-防火墙");
mapValue.put("连接时间","始终连接-有需要时连接-无连接");
mapValue.put("连接后身份认证方式","口令-数字认证技术-无认证");
mapValue.put("连接管理制度","审批备案-定期检查-风险评估-隔离措施有效性验证-无");
mapValue.put("合法系统间互联的识别和认证技术措施","有-无");
mapValue.put("移动存储介质使用管理制度","有-无");
mapValue.put("系统网络和公共网之间交叉使用移动存储介质","禁止-未禁止-未要求");
mapValue.put("工业控制系统主机的存储介质使用情况检查","定期-不定期-不检查");
mapValue.put("移动存储介质自动播放功能","明文禁止-未禁止-未要求");
mapValue.put("工业控制系统与其他系统之间专用的安全信息交换途径","有-无");
mapValue.put("移动存储介质销毁处置流程","有-无");
}
/*****************************************报表导出 end*********************************************************/

View File

@@ -16,7 +16,6 @@
<groupId>demo.xinwin</groupId>
<artifactId>demo-shiro-service</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -67,4 +67,12 @@ public class RedisConfig extends CachingConfigurerSupport {
return template;
}
}

View File

@@ -32,7 +32,10 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Shiro测试Controller
@@ -522,12 +525,14 @@ public class UserController {
// 获取当前的Subject
Subject currentUser = SecurityUtils.getSubject();
try {
// 在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查
// 每个Realm都能在必要时对提交的AuthenticationTokens作出反应
// 所以这一步在调用login(token)方法时,它会走到MyRealm.doGetAuthenticationInfo()方法中,具体验证方式详见此方法
logger.info("对用户[" + username + "]进行登录验证..验证开始");
currentUser.login(token);
logger.info("对用户[" + username + "]进行登录验证..验证通过");
//begin 添加记录日志功能
@@ -602,24 +607,6 @@ public class UserController {
}
//
// public Cookie getCookie(String cName,HttpServletRequest request) throws
// Exception
// {
// Cookie cookie=null;
// Cookie[] cs=this.getRequest().getCookies();
// if(cs!=null)
// {
// for(Cookie c:cs)
// {
// String name=c.getName();
// if(cName.equals(name))
// {
// cookie=c;
// }
// }
// }
// return cookie;
// }
}

View File

@@ -19,8 +19,6 @@ public class JedisShiroSessionRepository implements ShiroSessionRepository {
private static Logger logger = LoggerFactory.getLogger(JedisShiroSessionRepository.class);
private RedisTemplate<String, Object> objectRedisTemplate;
// @Autowired
// RedisTemplate<Object, Object> redisTemplate;
@Override
public void saveSession(Session session) {

View File

@@ -46,8 +46,7 @@ public class MyShiroRealm extends AuthorizingRealm{
/**
* 权限认证为当前登录的Subject授予角色和权限
* @see本例中该方法的调用时机为需授权资源被访问时
* @see 并且每次访问需授权资源时都会执行该方法中的逻辑这表明本例中默认并未启用AuthorizationCache
* @see 如果连续访问同一个URL比如刷新该方法不会被重复调用Shiro有一个时间间隔也就是cache时间在ehcache-shiro.xml中配置超过这个时间间隔再刷新页面该方法会被执行
* @see 如果连续访问同一个URL比如刷新该方法不会被重复调用Shiro有一个时间间隔系统提供三种cache内存ehcache redis在ehcache-shiro.xml中配置超过这个时间间隔再刷新页面该方法会被执行
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
@@ -65,13 +64,13 @@ public class MyShiroRealm extends AuthorizingRealm{
List<ShiroRole> roleList=user.getRoleList();
for (ShiroRole role : roleList) {
info.addStringPermissions(role.getPermissionsName());
// 或者按下面这样添加
// 添加一个角色,不是配置意义上的添加,而是证明该用户拥有admin角色
// info.addRole(role.getRoleName());
//添加权限
// info.addStringPermission("admin:manage");
}
// 或者按下面这样添加
// 添加一个角色,不是配置意义上的添加,而是证明该用户拥有admin角色
// info.addRole("admin");
//添加权限
// info.addStringPermission("admin:manage");
logger.info("已为用户[mike]赋予了[admin]角色和[admin:manage]权限");
return info;
}
// 返回null的话就会导致任何用户访问被拦截的请求时都会自动跳转到unauthorizedUrl指定的地址

View File

@@ -0,0 +1,97 @@
package com.xinwei.shiro;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.SerializationUtils;
import com.xinwei.utils.Constants;
public class RedisCache<K, V> implements Cache<K, V> {
private long expireTime = 120;// 缓存的超时时间单位为s
private String name;
private RedisTemplate<String, V> redisTemplate;// 通过构造方法注入该对象
// private RedisTemplate<K, V> redisTemplate;// 通过构造方法注入该对象
public RedisCache() {
super();
}
public RedisCache(long expireTime, RedisTemplate<String, V> redisTemplate,String name) {
super();
this.expireTime = expireTime;
this.redisTemplate = redisTemplate;
this.name=name;
}
/**
* 通过key来获取对应的缓存对象
* 通过源码我们可以发现shiro需要的key的类型为ObjectV的类型为AuthorizationInfo对象
*/
@Override
public V get(K key) throws CacheException {
//return redisTemplate.opsForValue().get(key);
V obj =redisTemplate.opsForValue().get(name+new String(SerializationUtils.serialize(getCacheKey(key))));
if(obj!=null)
{
System.out.println(obj.toString());
}
return obj;
}
/**
* 将权限信息加入缓存中
*/
@Override
public V put(K key, V value) throws CacheException {
// redisTemplate.opsForValue().set(key, value, this.expireTime, TimeUnit.SECONDS);
redisTemplate.opsForValue().set(name+new String(SerializationUtils.serialize(getCacheKey(key))), value, this.expireTime, TimeUnit.SECONDS);
return value;
}
/**
* 将权限信息从缓存中删除
*/
@Override
public V remove(K key) throws CacheException {
// V v = redisTemplate.opsForValue().get(key);
// redisTemplate.opsForValue().getOperations().delete(key);
V v = redisTemplate.opsForValue().get(name+new String(SerializationUtils.serialize(getCacheKey(key))));
redisTemplate.opsForValue().getOperations().delete(name+new String(SerializationUtils.serialize(getCacheKey(key))));
System.out.println("====removeremove========="+key+"===============");
return v;
}
@Override
public void clear() throws CacheException {
System.out.println("clearclearclearclearclearclearclearclearclear");
}
@Override
public int size() {
return 0;
}
@Override
public Set<K> keys() {
return null;
}
@Override
public Collection<V> values() {
return null;
}
private String getCacheKey(Object key) {
return Constants.REDIS_SHIRO_CACHE + ":" + key;
}
}

View File

@@ -0,0 +1,48 @@
package com.xinwei.shiro;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.util.Destroyable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import com.xinwei.spring.boot.autoconfigure.shiro.ShiroProperties;
/**
* @desc 该类提供redis cache。缓存 登录失败次数和用户权限。
* 过期时间分别对应application.yml 中的
* retry-expire-time-redis
* authorization-expire-time-redis
* @author wangxinwei
* @date 2018-02-07 04:23
*/
public class RedisCacheManager implements CacheManager, Destroyable {
private RedisTemplate redisTemplate;
private long expireTime;
@Autowired
private ShiroProperties properties;
public RedisCacheManager(RedisTemplate redisTemplateTemp){
redisTemplate = redisTemplateTemp;
}
@Override
public <K, V> Cache<K, V> getCache(String name) throws CacheException {
if(name.equals("passwordRetryCache")){
expireTime = properties.getRetryExpireTimeRedis();
}else{
expireTime = properties.getAuthorizationExpireTimeRedis();
}
return new RedisCache<K, V>(expireTime, redisTemplate,name);// 为了简化代码的编写此处直接new一个Cache
}
@Override
public void destroy() throws Exception {
}
}

View File

@@ -1,16 +1,31 @@
package com.xinwei.shiro;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.redis.core.RedisTemplate;
import com.xinwei.spring.boot.autoconfigure.shiro.ShiroProperties;
@Configuration
public class ShiroConfiguration {
@Autowired
public ShiroProperties properties;
/**
*
* 注释掉该方法时 shiro的登录会话session由ehcache保持。
* 打开该方法时shiro的登录回话session由redis保持。
* @param jedisShiroSessionRepository
@@ -24,6 +39,8 @@ public class ShiroConfiguration {
return customShiroSessionDAO;
}
@Bean
@DependsOn(value = { "objectRedisTemplate" })
public JedisShiroSessionRepository jedisShiroSessionRepository(RedisTemplate<String, Object> objectRedisTemplate) {
@@ -33,5 +50,45 @@ public class ShiroConfiguration {
}
/**
* (基于内存的)用户授权信息Cache
*/
@Bean(name = "shiroCacheManager")
@ConditionalOnMissingBean(name = "shiroCacheManager")
// @ConditionalOnMissingClass(value = {"org.apache.shiro.cache.ehcache.EhCacheManager"})
public CacheManager memoryCacheManager() {
return new MemoryConstrainedCacheManager();
}
/**
* (基于redis的)用户授权信息Cache
*/
@Bean(name = "shiroCacheManager")
@ConditionalOnMissingBean(name="shiroCacheManager")
public CacheManager redisCacheManager(RedisTemplate<String, Object> redisTemplate) {
return new RedisCacheManager(redisTemplate);
}
/**
* (基于ehcache的)用户授权信息Cache
*/
@Bean(name = "shiroCacheManager")
@ConditionalOnClass(name = {"org.apache.shiro.cache.ehcache.EhCacheManager"})
@ConditionalOnMissingBean(name = "shiroCacheManager")
public CacheManager ehcacheCacheManager() {
EhCacheManager ehCacheManager = new EhCacheManager();
ShiroProperties.Ehcache ehcache = properties.getEhcache();
if (ehcache.getCacheManagerConfigFile() != null) {
ehCacheManager.setCacheManagerConfigFile(ehcache.getCacheManagerConfigFile());
}
return ehCacheManager;
}
}

View File

@@ -3,12 +3,9 @@ shiro:
custom-authc-filter-class: com.xinwei.shiro.AjaxAuthorizationFilter
login-url: /login
success-url: /admin/sysFunctionManager/role_manager
unauthorized-url: /403
retry-max: 10000
sign-in:
user-param: username
password-param: password
remember-me-param: rememberMe
retry-max: 5
retry-expire-time-redis: 5
authorization-expire-time-redis: 10
hash-iterations: 1024
hash-algorithm-name: MD5
stored-credentials-hex-encoded: false
@@ -18,6 +15,5 @@ shiro:
validation-scheduler-enabled: true
filter-chain-definitions:
/media/**: anon
/user/edit/*: authc,perms[user:edit]
/admin/**: authc

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd" updateCheck="false">
<!-- 权限认证缓存20秒过期 -->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="20"
timeToLiveSeconds="0"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
/>
<!-- 登录次数缓存超过N次锁定 锁定10秒钟 -->
<cache name="passwordRetryCache"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="10"
timeToLiveSeconds="0"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120">
</cache>
</ehcache>

View File

@@ -1,4 +1,4 @@
log4j.rootLogger=INFO, console
log4j.rootLogger=DEBUG, console
#log4j.rootLogger=INFO, console, file
log4j.appender.console=org.apache.log4j.ConsoleAppender

View File

@@ -89,21 +89,7 @@ var TableManaged = function () {
// datatable.reload(null, false);
});
$("#editUser").on('click',function(){
var arr= setSelectAll();
if(arr[0]>1){
appcommon.alert("每次只能修改一条记录",0,2000);
return;
}
if(arr[0]==0){
appcommon.alert("请选择记录",0,2000);
return ;
}
toEditUserPage(arr[1]);
});
$("#delUser").on('click',function(){
var arr = setSelectAll();
@@ -340,36 +326,7 @@ function addUserSubmit(){
});
}
/**
* 获取待修改用户的值
*/
function toEditUserPage(username){
$.ajax({
url:'/admin/toEditUserPage',
type:'post',
data:'username='+username,
async : true,// 默认为true 异步
error:function(){
appcommon.alert("系统异常",2);
},
success:function(data){
var data = $.parseJSON(data);
$("#editUser-form input[name=company]").val(data.company);
$("#editUser-form input[name=email]").val(data.email);
$("#editUser-form input[name=position]").val(data.position);
$("#editUser-form input[name=fax]").val(data.fax);
$("#editUser-form input[name=mobile]").val(data.mobile);
$("#editUser-form input[name=realName]").val(data.realName);
$("#editUser-form input[name=username1]").val(data.username);
$("#editUser-form input[name=username]").val(data.username);
$('#Modal-EditUser').modal('show')
TableManaged.editUserValidator();
}
});
}
/**

View File

@@ -20,80 +20,9 @@
</div>
</div>
</div>
<div class="row" style="padding-top: 10px;">
<!-- 单位名称 -->
<div class="col-md-8 input-lg">
<div class="form-group form-group-lg">
<label class="col-sm-4 control-label">单位名称</label>
<div class="col-sm-8">
<input type="text" class="form-control input-lg" id="company" placeholder="单位名称" name="company" />
</div>
</div>
</div>
</div>
<div class="row" style="padding-top: 10px;">
<!-- 职务 -->
<div class="col-md-8 input-lg">
<div class="form-group form-group-lg">
<label class="col-sm-4 control-label">职务</label>
<div class="col-sm-8">
<input type="text" class="form-control input-lg" id="position" placeholder="职务" name="position" />
</div>
</div>
</div>
</div>
<div class="row" style="padding-top: 10px;">
<!-- 姓名 -->
<div class="col-md-8 input-lg">
<div class="form-group form-group-lg">
<label class="col-sm-4 control-label">姓名</label>
<div class="col-sm-8">
<input type="text" class="form-control input-lg" id="realName" placeholder="姓名" name="realName" />
</div>
</div>
</div>
</div>
<div class="row" style="padding-top: 10px;">
<!-- 联系电话 -->
<div class="col-md-8 input-lg">
<div class="form-group form-group-lg">
<label class="col-sm-4 control-label">联系电话</label>
<div class="col-sm-8">
<input type="text" class="form-control input-lg" id="mobile" placeholder="联系电话" name="mobile" />
</div>
</div>
</div>
</div>
<div class="row" style="padding-top: 10px;">
<!-- 邮箱 -->
<div class="col-md-8 input-lg">
<div class="form-group form-group-lg">
<label class="col-sm-4 control-label">邮箱</label>
<div class="col-sm-8">
<input type="text" class="form-control input-lg" id="email" placeholder="邮箱" name="email" />
</div>
</div>
</div>
</div>
<div class="row" style="padding-top: 10px;">
<!-- 传真 -->
<div class="col-md-8 input-lg">
<div class="form-group form-group-lg">
<label class="col-sm-4 control-label">传真</label>
<div class="col-sm-8">
<input type="text" class="form-control input-lg" id="fax" placeholder="传真" name="fax" />
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">

View File

@@ -1,110 +0,0 @@
<div>
<form id="editUser-form" class="form-horizontal" action="">
<div class="modal hide fade " id="Modal-EditUser">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"></button>
<h4 class="modal-title">添加用户</h4>
</div>
<div class="modal-body">
<div class="row" style="padding-top: 10px;">
<!-- 登录用户名 -->
<div class="col-md-8 input-lg">
<div class="form-group form-group-lg">
<label class="col-sm-4 control-label">登录用户名</label>
<div class="col-sm-8">
<input type="text" class="form-control input-lg" id="username1" placeholder="登录用户名" disabled name="username1" />
<input type="text" style="display:none" id="username" name="username" />
</div>
</div>
</div>
</div>
<div class="row" style="padding-top: 10px;">
<!-- 单位名称 -->
<div class="col-md-8 input-lg">
<div class="form-group form-group-lg">
<label class="col-sm-4 control-label">单位名称</label>
<div class="col-sm-8">
<input type="text" class="form-control input-lg" id="company" placeholder="单位名称" name="company" />
</div>
</div>
</div>
</div>
<div class="row" style="padding-top: 10px;">
<!-- 职务 -->
<div class="col-md-8 input-lg">
<div class="form-group form-group-lg">
<label class="col-sm-4 control-label">职务</label>
<div class="col-sm-8">
<input type="text" class="form-control input-lg" id="position" placeholder="职务" name="position" />
</div>
</div>
</div>
</div>
<div class="row" style="padding-top: 10px;">
<!-- 姓名 -->
<div class="col-md-8 input-lg">
<div class="form-group form-group-lg">
<label class="col-sm-4 control-label">姓名</label>
<div class="col-sm-8">
<input type="text" class="form-control input-lg" id="realName" placeholder="姓名" name="realName" />
</div>
</div>
</div>
</div>
<div class="row" style="padding-top: 10px;">
<!-- 联系电话 -->
<div class="col-md-8 input-lg">
<div class="form-group form-group-lg">
<label class="col-sm-4 control-label">联系电话</label>
<div class="col-sm-8">
<input type="text" class="form-control input-lg" id="mobile" placeholder="联系电话" name="mobile" />
</div>
</div>
</div>
</div>
<div class="row" style="padding-top: 10px;">
<!-- 邮箱 -->
<div class="col-md-8 input-lg">
<div class="form-group form-group-lg">
<label class="col-sm-4 control-label">邮箱</label>
<div class="col-sm-8">
<input type="text" class="form-control input-lg" id="email" placeholder="邮箱" name="email" />
</div>
</div>
</div>
</div>
<div class="row" style="padding-top: 10px;">
<!-- 传真 -->
<div class="col-md-8 input-lg">
<div class="form-group form-group-lg">
<label class="col-sm-4 control-label">传真</label>
<div class="col-sm-8">
<input type="text" class="form-control input-lg" id="fax" placeholder="传真" name="fax" />
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default pull-right" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" onclick="editUserSubmit();" >保存</button>
</div>
</div>
</div>
</div>
</form>
</div>

File diff suppressed because one or more lines are too long

65
demo-shiro-web/test Normal file
View File

@@ -0,0 +1,65 @@
/**
* 权限认证为当前登录的Subject授予角色和权限
* @see本例中该方法的调用时机为需授权资源被访问时
* @see 并且每次访问需授权资源时都会执行该方法中的逻辑这表明本例中默认并未启用AuthorizationCache
* @see 如果连续访问同一个URL比如刷新该方法不会被重复调用Shiro有一个时间间隔也就是cache时间在ehcache-shiro.xml中配置超过这个时间间隔再刷新页面该方法会被执行
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取当前登录输入的用户名,等价于(String) principalCollection.fromRealm(getName()).iterator().next();
String loginName = (String)super.getAvailablePrincipal(principalCollection);
//到数据库查是否有此对象
ShiroUser user= shiroUserService.findByUsername(loginName);
if(user!=null){
//权限信息对象info,用来存放查出的用户的所有的角色role及权限permission
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
//用户的角色集合
info.setRoles(user.getRolesName());
List<ShiroRole> roleList=user.getRoleList();
for (ShiroRole role : roleList) {
info.addStringPermissions(role.getPermissionsName());
}
return info;
}
// 返回null的话就会导致任何用户访问被拦截的请求时都会自动跳转到unauthorizedUrl指定的地址
return null;
}
/**
* 登录认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken authenticationToken) throws AuthenticationException {
//UsernamePasswordToken对象用来存放提交的登录信息
UsernamePasswordToken token=(UsernamePasswordToken) authenticationToken;
//查出是否有此用户
ShiroUser user= shiroUserService.findByUsername(token.getUsername());
if(user==null){
throw new UnknownAccountException();//账户不存在
}
if(user!=null&&user.getStatus().equals(Constants.userStatus_2)){
throw new LockedAccountException(); //账户被锁
}
if(user!=null&&user.getStatus().equals(Constants.userStatus_0)){
throw new DisabledAccountException();//账户不存在
}
if(user!=null&&user.getStatus().equals(Constants.userStatus_1)){
// 若存在将此用户存放到登录认证info中无需自己做密码对比Shiro会为我们进行密码对比校验
return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), ByteSource.Util.bytes("www"),getName());
}
return null;
}
}

View File

@@ -41,7 +41,7 @@
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
<scope>provided</scope>
<!-- <scope>provided</scope> -->
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>

View File

@@ -1,5 +1,7 @@
package com.xinwei.spring.boot.autoconfigure.shiro;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
@@ -10,14 +12,12 @@ import org.apache.shiro.cache.CacheManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.atomic.AtomicInteger;
public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher {
private static final Logger LOGGER = LoggerFactory.getLogger(RetryLimitHashedCredentialsMatcher.class);
private Cache<String, AtomicInteger> passwordRetryCache;
private int retryMax = 5;
private int retryMax;
public RetryLimitHashedCredentialsMatcher(CacheManager cacheManager) {
passwordRetryCache = cacheManager.getCache("passwordRetryCache");
@@ -27,13 +27,21 @@ public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws ExcessiveAttemptsException {
String username = (String)token.getPrincipal();
AtomicInteger retryCount = passwordRetryCache.get(username);
if(retryCount == null) {
retryCount = new AtomicInteger(0);
passwordRetryCache.put(username, retryCount);
}
if(retryCount.incrementAndGet() > retryMax) {
throw new ExcessiveAttemptsException("您已连续错误达" + retryMax + "次!请10分钟后再试");
throw new ExcessiveAttemptsException("您已连续错误达" + retryMax + "次!请N分钟后再试");
}
/**
* 使用redis 管理登录次数时, 需要此段代码注意只有redis需要内存和ehcache不需要
*/
if( passwordRetryCache.getClass().getName().contains("RedisCache")){
passwordRetryCache.put(username, retryCount);
}
boolean matches = super.doCredentialsMatch(token, info);

View File

@@ -5,6 +5,7 @@ import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.crypto.CipherService;
import org.apache.shiro.io.Serializer;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.RememberMeManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.AuthenticatingRealm;
@@ -12,19 +13,24 @@ import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.session.SessionListener;
import org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.SessionValidationScheduler;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.session.mgt.eis.SessionIdGenerator;
import org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.session.mgt.WebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -86,6 +92,8 @@ public class ShiroAutoConfiguration {
@Autowired(required = false)
private Collection<SessionListener> listeners;
@Bean(name = "mainRealm")
@ConditionalOnMissingBean(name = "mainRealm")
@ConditionalOnProperty(prefix = "shiro.realm.jdbc", name = "enabled", havingValue = "true")
@@ -121,17 +129,6 @@ public class ShiroAutoConfiguration {
return realm;
}
@Bean(name = "shiroCacheManager")
@ConditionalOnClass(name = {"org.apache.shiro.cache.ehcache.EhCacheManager"})
@ConditionalOnMissingBean(name = "shiroCacheManager")
public CacheManager ehcacheManager() {
EhCacheManager ehCacheManager = new EhCacheManager();
ShiroProperties.Ehcache ehcache = properties.getEhcache();
if (ehcache.getCacheManagerConfigFile() != null) {
ehCacheManager.setCacheManagerConfigFile(ehcache.getCacheManagerConfigFile());
}
return ehCacheManager;
}
@Bean
@ConditionalOnMissingBean(Cookie.class)

View File

@@ -2,7 +2,6 @@ package com.xinwei.spring.boot.autoconfigure.shiro;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.RememberMeManager;
import org.apache.shiro.realm.Realm;
@@ -11,13 +10,10 @@ import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.annotation.Order;
/**
* This guy is lazy, nothing left.
@@ -41,15 +37,6 @@ public class ShiroConfiguration {
return defaultAdvisorAutoProxyCreator;
}
/**
* (基于内存的)用户授权信息Cache
*/
@Bean(name = "shiroCacheManager")
@ConditionalOnMissingBean(name = "shiroCacheManager")
@ConditionalOnMissingClass(value = {"org.apache.shiro.cache.ehcache.EhCacheManager"})
public CacheManager shiroCacheManager() {
return new MemoryConstrainedCacheManager();
}
@Bean(name = "securityManager")
@DependsOn(value = {"shiroCacheManager", "rememberMeManager", "mainRealm"})
@@ -70,4 +57,6 @@ public class ShiroConfiguration {
aasa.setSecurityManager(securityManager);
return aasa;
}
}

View File

@@ -40,6 +40,39 @@ public class ShiroProperties {
*/
private int retryMax = 100;
/**
* 密码重试次数达到上限后,锁定时间(该参数仅适用于 redis管理cache
*/
private int retryExpireTimeRedis = 5;
/**
* 权限 缓存过期时间 (该参数仅适用于 redis管理cache
*/
private int AuthorizationExpireTimeRedis = 10;
public int getRetryExpireTimeRedis() {
return retryExpireTimeRedis;
}
public void setRetryExpireTimeRedis(int retryExpireTimeRedis) {
this.retryExpireTimeRedis = retryExpireTimeRedis;
}
public int getAuthorizationExpireTimeRedis() {
return AuthorizationExpireTimeRedis;
}
public void setAuthorizationExpireTimeRedis(int authorizationExpireTimeRedis) {
AuthorizationExpireTimeRedis = authorizationExpireTimeRedis;
}
private boolean storedCredentialsHexEncoded = true;
/**
@@ -140,9 +173,11 @@ public class ShiroProperties {
public static class Ehcache {
private String cacheManagerConfigFile = "classpath:org/apache/shiro/cache/ehcache/ehcache.xml";
// private String cacheManagerConfigFile = "classpath:org/apache/shiro/cache/ehcache/ehcache.xml";
public String getCacheManagerConfigFile() {
private String cacheManagerConfigFile = "classpath:ehcache.xml";
public String getCacheManagerConfigFile() {
return cacheManagerConfigFile;
}

27
sql/shiro_function.sql Normal file
View File

@@ -0,0 +1,27 @@
/*
-- Query: SELECT * FROM shiroDemo.shiro_function
LIMIT 0, 1000
-- Date: 2018-02-08 16:40
*/
INSERT INTO `shiro_function` (`id`,`create_time`,`function_name`,`permission_name`,`pid`) VALUES (1,NULL,'演示系统','1',0);
INSERT INTO `shiro_function` (`id`,`create_time`,`function_name`,`permission_name`,`pid`) VALUES (29,NULL,'系统管理功能','4',1);
INSERT INTO `shiro_function` (`id`,`create_time`,`function_name`,`permission_name`,`pid`) VALUES (30,NULL,'用户管理','4-1',29);
INSERT INTO `shiro_function` (`id`,`create_time`,`function_name`,`permission_name`,`pid`) VALUES (31,'2016-08-17 10:16:48','添加','4-1-add',30);
INSERT INTO `shiro_function` (`id`,`create_time`,`function_name`,`permission_name`,`pid`) VALUES (32,NULL,'功能管理','4-2',29);
INSERT INTO `shiro_function` (`id`,`create_time`,`function_name`,`permission_name`,`pid`) VALUES (34,NULL,'角色管理','4-3',29);
INSERT INTO `shiro_function` (`id`,`create_time`,`function_name`,`permission_name`,`pid`) VALUES (43,'2016-08-17 10:16:16','查询','4-1-search',30);
INSERT INTO `shiro_function` (`id`,`create_time`,`function_name`,`permission_name`,`pid`) VALUES (44,'2016-08-17 10:17:07','修改','4-1-edit',30);
INSERT INTO `shiro_function` (`id`,`create_time`,`function_name`,`permission_name`,`pid`) VALUES (45,'2016-08-17 10:17:13','审核','4-1-audit',30);
INSERT INTO `shiro_function` (`id`,`create_time`,`function_name`,`permission_name`,`pid`) VALUES (46,'2016-08-17 10:17:45','添加角色','4-1-role',30);
INSERT INTO `shiro_function` (`id`,`create_time`,`function_name`,`permission_name`,`pid`) VALUES (49,'2016-08-17 14:20:35','操作(增加,修改,删除,赋权限)','4-3-operate',34);
INSERT INTO `shiro_function` (`id`,`create_time`,`function_name`,`permission_name`,`pid`) VALUES (67,'2018-02-05 12:41:19','添加','4-2-add',32);
INSERT INTO `shiro_function` (`id`,`create_time`,`function_name`,`permission_name`,`pid`) VALUES (68,'2018-02-05 12:41:34','修改','4-2-edit',32);
INSERT INTO `shiro_function` (`id`,`create_time`,`function_name`,`permission_name`,`pid`) VALUES (69,'2018-02-05 12:41:44','删除','4-2-del',32);
INSERT INTO `shiro_function` (`id`,`create_time`,`function_name`,`permission_name`,`pid`) VALUES (70,'2018-02-05 12:45:35','添加','4-3-add',34);
INSERT INTO `shiro_function` (`id`,`create_time`,`function_name`,`permission_name`,`pid`) VALUES (72,'2018-02-05 12:46:15','删除','4-3-del',34);
INSERT INTO `shiro_function` (`id`,`create_time`,`function_name`,`permission_name`,`pid`) VALUES (73,'2018-02-05 12:46:23','修改','4-3-edit',34);
INSERT INTO `shiro_function` (`id`,`create_time`,`function_name`,`permission_name`,`pid`) VALUES (74,'2018-02-05 12:47:10','角色添加功能','4-3-role-func',34);
INSERT INTO `shiro_function` (`id`,`create_time`,`function_name`,`permission_name`,`pid`) VALUES (75,'2018-02-05 12:54:40','测试菜单','1-test',1);
INSERT INTO `shiro_function` (`id`,`create_time`,`function_name`,`permission_name`,`pid`) VALUES (76,'2018-02-05 12:55:14','测试-1','2-1',75);
INSERT INTO `shiro_function` (`id`,`create_time`,`function_name`,`permission_name`,`pid`) VALUES (77,'2018-02-05 12:57:17','测试2','2-2',75);

7
sql/shiro_role.sql Normal file
View File

@@ -0,0 +1,7 @@
/*
-- Query: SELECT * FROM shiroDemo.shiro_role
LIMIT 0, 1000
-- Date: 2018-02-08 16:41
*/
INSERT INTO `shiro_role` (`id`,`create_time`,`role_name`) VALUES (1,'2018-02-05 11:22:09','管理员');

View File

@@ -0,0 +1,23 @@
/*
-- Query: SELECT * FROM shiroDemo.shiro_role_function
LIMIT 0, 1000
-- Date: 2018-02-08 16:41
*/
INSERT INTO `shiro_role_function` (`role_id`,`function_id`) VALUES (1,1);
INSERT INTO `shiro_role_function` (`role_id`,`function_id`) VALUES (1,29);
INSERT INTO `shiro_role_function` (`role_id`,`function_id`) VALUES (1,30);
INSERT INTO `shiro_role_function` (`role_id`,`function_id`) VALUES (1,31);
INSERT INTO `shiro_role_function` (`role_id`,`function_id`) VALUES (1,43);
INSERT INTO `shiro_role_function` (`role_id`,`function_id`) VALUES (1,44);
INSERT INTO `shiro_role_function` (`role_id`,`function_id`) VALUES (1,45);
INSERT INTO `shiro_role_function` (`role_id`,`function_id`) VALUES (1,46);
INSERT INTO `shiro_role_function` (`role_id`,`function_id`) VALUES (1,32);
INSERT INTO `shiro_role_function` (`role_id`,`function_id`) VALUES (1,67);
INSERT INTO `shiro_role_function` (`role_id`,`function_id`) VALUES (1,68);
INSERT INTO `shiro_role_function` (`role_id`,`function_id`) VALUES (1,69);
INSERT INTO `shiro_role_function` (`role_id`,`function_id`) VALUES (1,34);
INSERT INTO `shiro_role_function` (`role_id`,`function_id`) VALUES (1,49);
INSERT INTO `shiro_role_function` (`role_id`,`function_id`) VALUES (1,75);
INSERT INTO `shiro_role_function` (`role_id`,`function_id`) VALUES (1,76);
INSERT INTO `shiro_role_function` (`role_id`,`function_id`) VALUES (1,77);

8
sql/shiro_user.sql Normal file
View File

@@ -0,0 +1,8 @@
/*
-- Query: SELECT * FROM shiroDemo.shiro_user
LIMIT 0, 1000
-- Date: 2018-02-08 16:41
*/
INSERT INTO `shiro_user` (`id`,`create_time`,`password`,`status`,`username`) VALUES (2,NULL,'5VIGn1Yz66kevrJEWjT4pw==','1','admin');
INSERT INTO `shiro_user` (`id`,`create_time`,`password`,`status`,`username`) VALUES (47,'2018-02-05 17:05:02','cSbmvFebb1glkQvPG02RgA==','1','test');

8
sql/shiro_user_role.sql Normal file
View File

@@ -0,0 +1,8 @@
/*
-- Query: SELECT * FROM shiroDemo.shiro_user_role
LIMIT 0, 1000
-- Date: 2018-02-08 16:42
*/
INSERT INTO `shiro_user_role` (`user_id`,`role_id`) VALUES (2,1);
INSERT INTO `shiro_user_role` (`user_id`,`role_id`) VALUES (47,1);