权限控制常用的有shiro、spring security,两者相比较,各有优缺点,此篇文章以shiro为例,实现系统的权限控制。

一、数据库的设计

简单的五张表,用户、角色、权限及关联表:

CREATE TABLE `sysrole` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(255) NOT NULL,
`role` varchar(255) NOT NULL COMMENT '角色名',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='角色表'; CREATE TABLE `sysuser` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`username` varchar(250) NOT NULL,
`password` varchar(250) NOT NULL,
`salt` varchar(250) NOT NULL COMMENT '密码盐',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='用户表'; CREATE TABLE `user_role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`role_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='用户角色表'; CREATE TABLE `syspermission` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(250) NOT NULL COMMENT '权限名称',
`type` int(1) NOT NULL COMMENT '权限类型,1菜单menu,2按钮button,3数据data',
`permission` varchar(250) NOT NULL COMMENT '权限表达式',
`parent_id` int(11) NOT NULL COMMENT '父级ID',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 COMMENT='权限表'; CREATE TABLE `role_permission` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`role_id` int(11) NOT NULL,
`permission_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8 COMMENT='角色权限表';

二、配置shiro

1.pom.xml文件中引入shiro的jar包

     <dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency> <dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.3.2</version>
</dependency> <dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.3.2</version>
</dependency> <dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-guice</artifactId>
<version>1.3.2</version>
</dependency>

2、编写shiro的配置文件

import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map; import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.SessionListener;
import org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
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.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; @Configuration
public class ShiroConfig { private static Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); //缓存管理器
@Bean(name = "cacheShiroManager")
public EhCacheManager getCacheManager(){
return new EhCacheManager();
} //生命周期处理器
@Bean(name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor(){
return new LifecycleBeanPostProcessor();
} //hash加密处理
@Bean(name = "hashedCredentialsMatcher")
public HashedCredentialsMatcher getHashedCredentialsMatcher(){
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
credentialsMatcher.setHashAlgorithmName("MD5");
credentialsMatcher.setHashIterations(2);//散列的次数,比如散列两次,相当于 md5(md5(""));
credentialsMatcher.setStoredCredentialsHexEncoded(true);
return credentialsMatcher;
} //浏览器会话的cookie管理
@Bean(name = "sessionIdCookie")
public SimpleCookie getSessionIdCookie(){
SimpleCookie cookie = new SimpleCookie("sid");
cookie.setHttpOnly(true);
cookie.setMaxAge(-1);//浏览器关闭时失效此Cookie;
return cookie;
} //记住我的cookie管理
@Bean(name = "rememberMeCookie")
public SimpleCookie getRememberMeCookie(){
SimpleCookie cookie = new SimpleCookie("rememberMe");
//如果httyOnly设置为true,则客户端不会暴露给客户端脚本代码,使用HttpOnly cookie有助于减少某些类型的跨站点脚本攻击;
cookie.setHttpOnly(true);
cookie.setMaxAge(2592000);//记住我的cookie有效期30天
return cookie;
} //记住我cookie管理器
@Bean
public CookieRememberMeManager getRememberManager(){
CookieRememberMeManager meManager = new CookieRememberMeManager();
meManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));
meManager.setCookie(getRememberMeCookie());
return meManager;
} //session验证管理器
@Bean(name = "sessionValidationScheduler")
public ExecutorServiceSessionValidationScheduler getExecutorServiceSessionValidationScheduler(){
ExecutorServiceSessionValidationScheduler scheduler = new ExecutorServiceSessionValidationScheduler();
//设置session验证时间,15分钟一次
scheduler.setInterval(900000);
return scheduler;
} @Bean(name = "sessionManager")
public DefaultWebSessionManager getSessionManage(){ DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setGlobalSessionTimeout(1800000);//过期时间30分钟
//session定期验证
sessionManager.setSessionValidationScheduler(getExecutorServiceSessionValidationScheduler());
sessionManager.setDeleteInvalidSessions(true);
//会话cookie
sessionManager.setSessionIdCookie(getSessionIdCookie());
sessionManager.setSessionIdCookieEnabled(true);
sessionManager.setSessionValidationSchedulerEnabled(true);
//session监听
LinkedList<SessionListener> list = new LinkedList<SessionListener>();
list.add(new MyShiroSessionListener());
sessionManager.setSessionListeners(list);
//session的存储
EnterpriseCacheSessionDAO cacheSessionDAO = new EnterpriseCacheSessionDAO();
sessionManager.setCacheManager(getCacheManager());
sessionManager.setSessionDAO(cacheSessionDAO);
return sessionManager;
} @Bean(name = "myRealm")
public AuthorizingRealm getShiroRealm(){
AuthorizingRealm realm = new MyShiroRealm(getCacheManager(),getHashedCredentialsMatcher());
realm.setName("my_shiro_auth_cache");
// realm.setAuthenticationCache(getCacheManager().getCache(realm.getName()));
realm.setAuthenticationTokenClass(UsernamePasswordToken.class);
realm.setCredentialsMatcher(getHashedCredentialsMatcher());
return realm;
} @Bean(name = "securityManager")
public DefaultWebSecurityManager getSecurityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setCacheManager(getCacheManager());
securityManager.setRealm(getShiroRealm());
securityManager.setRememberMeManager(getRememberManager());
securityManager.setSessionManager(getSessionManage());
return securityManager;
} @Bean
public MethodInvokingFactoryBean getMethodInvokingFactoryBean(){
MethodInvokingFactoryBean factoryBean = new MethodInvokingFactoryBean();
factoryBean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
factoryBean.setArguments(new Object[]{getSecurityManager()});
return factoryBean;
} @Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator getAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true);
return creator;
} @Bean
public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(){
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(getSecurityManager());
return advisor;
} @Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(){
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
factoryBean.setSecurityManager(getSecurityManager());
//设置登录页面路径
factoryBean.setLoginUrl("/login");
//设置登录成功跳转的路径,此方法有bug
     // factoryBean.setSuccessUrl("/manager/hello");
//将无需拦截的方法及页面使用anon配置
filterChainDefinitionMap.put("", "anon");
//将需认证的方法及页面使用authc配置
filterChainDefinitionMap.put("", "authc");

factoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return factoryBean;
} @Bean(name = "shiroDialect")
public ShiroDialect shiroDialect(){
return new ShiroDialect();
} }

3、自定义shiroRealm

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.thymeleaf.util.StringUtils; public class MyShiroRealm extends AuthorizingRealm {
//注入查询用户信息的service层
@Resource
private IAuthorityService authorityService; private Logger log = Logger.getLogger(MyShiroRealm.class);
public MyShiroRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
super(cacheManager, matcher);
} //授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) { SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
SysUser user = (SysUser) principals.getPrimaryPrincipal();
for(SysRole role:user.getRoleList()){
authorizationInfo.addRole(role.getRole());
for(SysPermission p:role.getPermissions()){
authorizationInfo.addStringPermission(p.getPermission());
}
} return authorizationInfo; }    //认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken user = (UsernamePasswordToken) token;
String username = user.getUsername();
String password = user.getPassword().toString();
user.isRememberMe(); if(StringUtils.isEmpty(username)){
throw new IncorrectCredentialsException("username is null");
}else if(StringUtils.isEmpty(password)){
throw new IncorrectCredentialsException("password is null");
}
//根据账户名称查询用户信息
SysUser sysUser = authorityService.findByUsername(username);
if(sysUser == null){
log.error("用户不存在"+username);
return null;
}
     //密码加密策略可自定义,此处使用自定义的密码盐CredentialsSalt
    SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(sysUser,sysUser.getPassword(), ByteSource.Util.bytes(sysUser.getCredentialsSalt()),getName());
    return authenticationInfo;
  }
}

4、自定义session监听

import org.apache.log4j.Logger;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.SessionListener; public class MyShiroSessionListener implements SessionListener { private Logger log = Logger.getLogger(MyShiroSessionListener.class);
@Override
public void onStart(Session session) {
log.info("----会话创建:"+session.getId());
} @Override
public void onStop(Session session) {
log.info("----会话停止:"+session.getId());
} @Override
public void onExpiration(Session session) {
log.info("----会话过期:"+session.getId());
} }

三、使用注解控制后台方法的权限

@RequiresAuthentication,认证通过可访问

@RequiresPermissions("***"),有***权限可访问

@RequiresGuest,游客即可访问

@RequiresRoles("***"),有***角色可访问

@RequiresUser("***"),是***用户可访问

四、使用shiro标签细粒度控制页面按钮及数据的权限

thyemleaf模板引入shiro标签库

<html xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">

<shiro:guest/>
<shiro:user/>
<shiro:principal/>
<shiro:hasPermission/>
<shiro:lacksPermission/>
<shiro:hasRole/>
<shiro:lacksRole/>
<shiro:hasAnyRoles/>
<shiro:authenticated/>
<shiro:notAuthenticated/>

使用方法参考:shiro官网

shiro权限控制的简单实现的更多相关文章

  1. shiro权限控制入门

    一:权限控制两种主要方式 粗粒度 URL 级别权限控制和细粒度方法级别权限控制 1.粗粒度 URL 级别权限控制 可以基于 Filter 实现在数据库中存放 用户.权限.访问 URL 对应关系, 当前 ...

  2. Spring boot后台搭建二为Shiro权限控制添加缓存

    在添加权限控制后,添加方法 查看 当用户访问”获取用户信息”.”新增用户”和”删除用户”的时,后台输出打印如下信息 , Druid数据源SQL监控 为了避免频繁访问数据库获取权限信息,在Shiro中加 ...

  3. Spring boot后台搭建二集成Shiro权限控制

    上一篇文章,实现了用户验证 查看,接下来实现下权限控制 权限控制,是管理资源访问的过程,用于对用户进行的操作授权,证明该用户是否允许进行当前操作,如访问某个链接,某个资源文件等 Apache Shir ...

  4. shiro权限控制配置

    shiro配置流程 web.xml中配置shiro的filter spring中配置shiro的过滤器工厂,指定对不同地址权限控制 , 传入安全管理器 配置安全管理器,传入realm,realm中定义 ...

  5. ASP.NET MVC中权限控制的简单实现

    1.重写AuthorizeAttribute类,用自己的权限控制逻辑重写AuthorizeCore方法 public class MyAuthorizeAttribute : AuthorizeAtt ...

  6. shiro权限控制

    1.1  简介 Apache Shiro是Java的一个安全框架.目前,使用Apache Shiro的人越来越多,因为它相当简单,对比Spring Security,可能没有Spring Securi ...

  7. Shiro权限控制框架

    Subject:主体,可以看到主体可以是任何可以与应用交互的"用户": SecurityManager:相当于SpringMVC中的DispatcherServlet或者Strut ...

  8. shiro权限控制(一):shiro介绍以及整合SSM框架

    shiro安全框架是目前为止作为登录注册最常用的框架,因为它十分的强大简单,提供了认证.授权.加密和会话管理等功能 . shiro能做什么? 认证:验证用户的身份 授权:对用户执行访问控制:判断用户是 ...

  9. JFinal配合Shiro权限控制在FreeMarker模板引擎中控制到按钮粒度的使用

    实现在FreeMarker模板中控制对应按钮的显示隐藏主要用到了Shiro中的hasRole, hasAnyRoles, hasPermission以及Authenticated等方法,我们可以实现T ...

随机推荐

  1. ItemCF_基于物品的协同过滤_MapReduceJava代码实现思路

    ItemCF_基于物品的协同过滤 1.    概念 2.    原理 如何给用户推荐? 给用户推荐他没有买过的物品--103 3.    java代码实现思路 数据集: 第一步:构建物品的同现矩阵 第 ...

  2. 【开发技术】eclipse中格式化代码快捷键Ctrl+Shift+F失效的解决办法

    要格式化代码的时候,右键-source-format能够起效,但ctrl+shift+f不好使了. 原来是和“简繁体快捷键”冲突了.输入法中的这个快捷键我们一般不用,小勾勾去掉就成了. eclipse ...

  3. PostgresSQL中的限制和级联删除

    摘录自:http://www.mamicode.com/info-detail-879792.html 删除和更新时对应的操作是一样的

  4. Struts的session问题

    问题描述: 在一个action中设置session之后,在jsp中得不到session的值或者在另一个action中得不到session的值. 解决方案: 1.不要把session设置成为静态的,同时 ...

  5. MySQL 取得小时分钟部分

    MySQL 取得小时分钟部分 SELECT `CpParkID` , DATE_FORMAT( `UPDATE_TIME` , '%H:%i' )FROM `cp_park`WHERE HOUR( ` ...

  6. linux_ssh

    什么是ssh? 配置文件位置:/etc/ssh/sshd_config 远程登录和为其他网络提供安全的加密数据传输协议,默认端口22,默认协议是SSH2 # 远程终端通过ssh连接服务器管理服务器 # ...

  7. python_如何为元组中每个元素命名

    学生信息系统: (名字,年龄,性别,邮箱地址) 为了减少存储开支,每个学生的信息都以一个元组形式存放 如: ('tom', 18,'male','tom@qq.com' ) ('jom', 18,'m ...

  8. MySQL两大存储引擎InnoDB与MyISAM

    1.InnoDB存储引擎 MySQL5.5中InnoDB成为默认的存储引擎.InnoDB是事务型存储引擎,被设计用来处理大量的短期事务.它的性能和自动崩溃恢复特性,使得它在非事务场景中也很流行. 所以 ...

  9. 绕过js验证

    我在火狐和谷歌下想删除对应js,由于是外部js引入的,没删掉.只好借用了工具. 这个工具也并不是多么的高大上,也许大家都用过,httprequester 步骤:打开火狐附加组件管理器——扩展——输入h ...

  10. 转-Linux硬件装置和磁盘分区MBR

    1 各硬件装置在Linux中的文件名 『在Linux系统中,每个装置都被当成一个文件来对待』 举例来说,SATA接口的硬盘的文件名即为/dev/sd[a-d],其中, 括号内的字母为a-d当中的任意一 ...