1.依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>3.0.0</version>
</dependency>
2.数据库表结构
DROP TABLE IF EXISTS `t_authority`;
CREATE TABLE `t_authority` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`authority_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '' COMMENT '权限名称',
`icon` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '' COMMENT '图标',
`uri` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '' COMMENT '请求uri 分隔,',
`permission` varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of t_authority
-- ----------------------------
INSERT INTO `t_authority` VALUES (1, '查询用户列表', '', '/user/list', 'roles[admin,普通用户]');
INSERT INTO `t_authority` VALUES (2, '查询角色列表', '', '/role/list', 'roles[admin]');
SET FOREIGN_KEY_CHECKS = 1;
DROP TABLE IF EXISTS `t_role`;
CREATE TABLE `t_role` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`role_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '' COMMENT '角色名称',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of t_role
-- ----------------------------
INSERT INTO `t_role` VALUES (1, 'admin');
INSERT INTO `t_role` VALUES (2, '普通用户');
SET FOREIGN_KEY_CHECKS = 1;
DROP TABLE IF EXISTS `t_role_authority`;
CREATE TABLE `t_role_authority` (
`role_id` int(11) NOT NULL DEFAULT 0 COMMENT '角色id',
`authority_id` int(11) NOT NULL DEFAULT 0 COMMENT '权限id',
PRIMARY KEY (`role_id`, `authority_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of t_role_authority
-- ----------------------------
INSERT INTO `t_role_authority` VALUES (1, 1);
INSERT INTO `t_role_authority` VALUES (1, 2);
INSERT INTO `t_role_authority` VALUES (2, 1);
SET FOREIGN_KEY_CHECKS = 1;
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`username` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '' COMMENT '用户名',
`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '' COMMENT '密码',
`role_id` int(11) DEFAULT 0 COMMENT '角色id',
`state` int(11) DEFAULT 0 COMMENT '账户状态0正常 1锁定',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of t_user
-- ----------------------------
INSERT INTO `t_user` VALUES (1, 'admin', 'a84ddb3db4aeeeebc3f357ac780bee7c', 1, 0);
INSERT INTO `t_user` VALUES (2, 'guest', 'a8a68069ad186d2672ea7e9be9183473', 2, 0);
SET FOREIGN_KEY_CHECKS = 1;
3.对应的mapper,entity。。。
4.config
@Configuration
public class ShiroConfig {
private static final String REMEMBER_ME_COOKIE = "remenbermeCookie";
private static final String COOKIE_NAME = "shiro:cookie:";
private static final long SESSION_TIME=1000*60*30;
/**
* 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
* 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能
* @return
*/
/**
* shiro管理生命周期的东西
*/
@Bean(name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
@DependsOn({"lifecycleBeanPostProcessor"})
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
/**
* anon(匿名)、logout(登出)、authc(认证)
*/
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager, ShiroService shiroService) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
shiroFilter.setLoginUrl("/user/no/login");
shiroFilter.setSuccessUrl("/user/success");
shiroFilter.setUnauthorizedUrl("/user/fail");
Map<String, Filter> filterMap = new LinkedHashMap<>(1);
//自定义角色过滤器
filterMap.put("roles", rolesAuthorizationFilter());
shiroFilter.setFilters(filterMap);
// 过滤链可以使用注解形式实现
shiroFilter.setFilterChainDefinitionMap(shiroService.loadFilterChainDefinitions());
return shiroFilter;
}
/**
* 自定义角色过滤器
*/
@Bean
public CustomRolesAuthorizationFilter rolesAuthorizationFilter() {
return new CustomRolesAuthorizationFilter();
}
/**
* 安全管理模块,所有的manager在此配置
*/
@Bean("securityManager")
public DefaultWebSecurityManager securityManager(@Qualifier("shiroRedisTemplate")RedisTemplate redisTemplate) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//自定义realm
securityManager.setRealm(myShiroRealm(redisTemplate));
//自定义session管理 使用redis
securityManager.setSessionManager(sessionManager(redisTemplate));
//自定义缓存实现 使用redis
securityManager.setCacheManager(redisCacheManager());
//注入记住我管理器;
securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}
/**
* 领域
*/
@Bean(name = "myShiroRealm")
@DependsOn(value = {"lifecycleBeanPostProcessor", "ShiroRedisCacheManager"})
public MyShiroRealm myShiroRealm(@Qualifier("shiroRedisTemplate")RedisTemplate redisTemplate) {
MyShiroRealm shiroRealm = new MyShiroRealm();
//设置缓存管理器
shiroRealm.setCacheManager(redisCacheManager());
shiroRealm.setCachingEnabled(true);
//设置认证密码算法及迭代复杂度
shiroRealm.setCredentialsMatcher(retryLimitHashedCredentialsMatcher());
//认证
shiroRealm.setAuthenticationCachingEnabled(true);
//授权
shiroRealm.setAuthorizationCachingEnabled(true);
return shiroRealm;
}
/**
* 自定义配置密码比较器
*
*/
@Bean("credentialsMatcher")
public RetryLimitHashedCredentialsMatcher retryLimitHashedCredentialsMatcher(){
RetryLimitHashedCredentialsMatcher retryLimitHashedCredentialsMatcher = new RetryLimitHashedCredentialsMatcher();
//如果密码加密,可以打开下面配置
//加密算法的名称
retryLimitHashedCredentialsMatcher.setHashAlgorithmName("md5");
//配置加密的次数
retryLimitHashedCredentialsMatcher.setHashIterations(2);
//是否存储为16进制
retryLimitHashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
return retryLimitHashedCredentialsMatcher;
}
/**
* 缓存管理器的配置
*/
@Bean(name = "ShiroRedisCacheManager")
public ShiroRedisCacheManager redisCacheManager() {
ShiroRedisCacheManager redisCacheManager = new ShiroRedisCacheManager();
redisCacheManager.createCache(RedisKey.CACHE_KEY);
return redisCacheManager;
}
/**
* 配置sessionmanager,由redis存储数据
*/
@Bean(name = "sessionManager")
@DependsOn(value = "lifecycleBeanPostProcessor")
public ShiroSessionManager sessionManager(@Qualifier("shiroRedisTemplate") RedisTemplate redisTemplate) {
//自定义sessionManage解决单次请求需要多次访问redis
ShiroSessionManager sessionManager = new ShiroSessionManager();
//redisSessionDao
MyRedisSessionDao redisSessionDao = new MyRedisSessionDao(SESSION_TIME,redisTemplate);
sessionManager.setSessionDAO(redisSessionDao);
//删除无效会话
sessionManager.setDeleteInvalidSessions(true);
//设置对应的cookie
SimpleCookie cookie = new SimpleCookie();
cookie.setName(COOKIE_NAME);
cookie.setMaxAge(180000);
sessionManager.setSessionIdCookie(cookie);
sessionManager.setSessionIdCookieEnabled(true);
return sessionManager;
}
/**
*
* remenberMeCookie是一个实现了将用户名保存在客户端的一个cookie,与登陆时的cookie是两个simpleCookie。
* 登陆时会根据权限去匹配,如是user权限,则不会先去认证模块认证,而是先去搜索cookie中是否有rememberMeCookie,
* 如果存在该cookie,则可以绕过认证模块,直接寻找授权模块获取角色权限信息。
* 如果权限是authc,则仍会跳转到登陆页面去进行登陆认证.
*/
@Bean
public SimpleCookie rememberMeCookie() {
SimpleCookie simpleCookie = new SimpleCookie(REMEMBER_ME_COOKIE);
simpleCookie.setHttpOnly(true);
//30天
simpleCookie.setMaxAge(2592000);
return simpleCookie;
}
/**
* cookie管理对象;记住我功能
*/
@Bean
public CookieRememberMeManager rememberMeManager() {
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
//rememberMe cookie加密的密钥 默认AES算法 密钥长度(128 256 512 位)
cookieRememberMeManager.setCipherKey(Base64.decode("6ZmI6I2j5Y+R5aSn5ZOlAA=="));
return cookieRememberMeManager;
}