项目下载地址:http://download.csdn.NET/detail/aqsunkai/9805821

(一)在pom.xml中添加依赖:

  1. <properties>
  2. <shiro.version>1.3.2</shiro.version>
  3. </properties>
  1. <!--shiro start-->
  2. <dependency>
  3. <groupId>org.apache.shiro</groupId>
  4. <artifactId>shiro-core</artifactId>
  5. <version>${shiro.version}</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.apache.shiro</groupId>
  9. <artifactId>shiro-web</artifactId>
  10. <version>${shiro.version}</version>
  11. </dependency>
  12. <dependency>
  13. <groupId>org.apache.shiro</groupId>
  14. <artifactId>shiro-ehcache</artifactId>
  15. <version>${shiro.version}</version>
  16. </dependency>
  17. <dependency>
  18. <groupId>org.apache.shiro</groupId>
  19. <artifactId>shiro-spring</artifactId>
  20. <version>${shiro.version}</version>
  21. </dependency>
  22. <!--shiro end-->

下面是数据库的表,这里主要涉及到五张表:用户表,角色表(用户所拥有的角色),权限表(角色所涉及到的权限),用户-角色表(用户和角色是多对多的),角色-权限表(角色和权限是多对多的)。sql语句如下:

  1. -- ----------------------------
  2. -- Table structure for sys_permission
  3. -- ----------------------------
  4. DROP TABLE IF EXISTS `sys_permission`;
  5. CREATE TABLE `sys_permission` (
  6. `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  7. `url` varchar(256) DEFAULT NULL COMMENT 'url地址',
  8. `name` varchar(64) DEFAULT NULL COMMENT 'url描述/名称',
  9. parent_id int(11) DEFAULT NULL COMMENT '父节点权限ID',
  10. PRIMARY KEY (`id`)
  11. ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  12. -- ----------------------------
  13. -- Records of sys_permission
  14. -- ----------------------------
  15. INSERT INTO `sys_permission` VALUES ('10', '/member/changeSessionStatus.shtml', '用户Session踢出',null);
  16. INSERT INTO `sys_permission` VALUES ('11', '/member/forbidUserById.shtml', '用户激活&禁止',null);
  17. INSERT INTO `sys_permission` VALUES ('12', '/member/deleteUserById.shtml', '用户删除',null);
  18. INSERT INTO `sys_permission` VALUES ('13', '/permission/addPermission2Role.shtml', '权限分配',null);
  19. INSERT INTO `sys_permission` VALUES ('14', '/role/clearRoleByUserIds.shtml', '用户角色分配清空',null);
  20. INSERT INTO `sys_permission` VALUES ('15', '/role/addRole2User.shtml', '角色分配保存',null);
  21. INSERT INTO `sys_permission` VALUES ('16', '/role/deleteRoleById.shtml', '角色列表删除',null);
  22. INSERT INTO `sys_permission` VALUES ('17', '/role/addRole.shtml', '角色列表添加',null);
  23. INSERT INTO `sys_permission` VALUES ('18', '/role/index.shtml', '角色列表',null);
  24. INSERT INTO `sys_permission` VALUES ('19', '/permission/allocation.shtml', '权限分配',null);
  25. INSERT INTO `sys_permission` VALUES ('20', '/role/allocation.shtml', '角色分配',null);
  26. INSERT INTO `sys_permission` VALUES ('4', '/permission/index.shtml', '权限列表',null);
  27. INSERT INTO `sys_permission` VALUES ('6', '/permission/addPermission.shtml', '权限添加',null);
  28. INSERT INTO `sys_permission` VALUES ('7', '/permission/deletePermissionById.shtml', '权限删除',null);
  29. INSERT INTO `sys_permission` VALUES ('8', '/member/list.shtml', '用户列表',null);
  30. INSERT INTO `sys_permission` VALUES ('9', '/member/online.shtml', '在线用户',null);
  31. -- ----------------------------
  32. -- Table structure for sys_role
  33. -- ----------------------------
  34. DROP TABLE IF EXISTS `sys_role`;
  35. CREATE TABLE `sys_role` (
  36. `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  37. `name` varchar(32) DEFAULT NULL COMMENT '角色名称',
  38. `type` varchar(10) DEFAULT NULL COMMENT '角色类型',
  39. PRIMARY KEY (`id`)
  40. ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  41. -- ----------------------------
  42. -- Records of sys_role
  43. -- ----------------------------
  44. INSERT INTO `sys_role` VALUES ('1', '系统管理员', '100004');
  45. INSERT INTO `sys_role` VALUES ('3', '权限角色', '100001');
  46. INSERT INTO `sys_role` VALUES ('4', '用户中心', '100002');
  47. INSERT INTO `sys_role` VALUES ('0', '角色管理', '100003');
  48. -- ----------------------------
  49. -- Table structure for sys_role_permission
  50. -- ----------------------------
  51. DROP TABLE IF EXISTS `sys_role_permission`;
  52. CREATE TABLE `sys_role_permission` (
  53. `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  54. `rid` varchar(64) DEFAULT NULL COMMENT '角色ID',
  55. `pid` varchar(64) DEFAULT NULL COMMENT '权限ID',
  56. PRIMARY KEY (`id`)
  57. ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  58. -- ----------------------------
  59. -- Records of sys_role_permission
  60. -- ----------------------------
  61. INSERT INTO `sys_role_permission` VALUES ('1', '4', '8');
  62. INSERT INTO `sys_role_permission` VALUES ('10', '3', '14');
  63. INSERT INTO `sys_role_permission` VALUES ('11', '3', '15');
  64. INSERT INTO `sys_role_permission` VALUES ('12', '3', '16');
  65. INSERT INTO `sys_role_permission` VALUES ('13', '3', '17');
  66. INSERT INTO `sys_role_permission` VALUES ('14', '3', '18');
  67. INSERT INTO `sys_role_permission` VALUES ('15', '3', '19');
  68. INSERT INTO `sys_role_permission` VALUES ('16', '3', '20');
  69. INSERT INTO `sys_role_permission` VALUES ('17', '1', '4');
  70. INSERT INTO `sys_role_permission` VALUES ('18', '1', '6');
  71. INSERT INTO `sys_role_permission` VALUES ('19', '1', '7');
  72. INSERT INTO `sys_role_permission` VALUES ('2', '4', '9');
  73. INSERT INTO `sys_role_permission` VALUES ('20', '1', '8');
  74. INSERT INTO `sys_role_permission` VALUES ('21', '1', '9');
  75. INSERT INTO `sys_role_permission` VALUES ('22', '1', '10');
  76. INSERT INTO `sys_role_permission` VALUES ('23', '1', '11');
  77. INSERT INTO `sys_role_permission` VALUES ('24', '1', '12');
  78. INSERT INTO `sys_role_permission` VALUES ('25', '1', '13');
  79. INSERT INTO `sys_role_permission` VALUES ('26', '1', '14');
  80. INSERT INTO `sys_role_permission` VALUES ('27', '1', '15');
  81. INSERT INTO `sys_role_permission` VALUES ('28', '1', '16');
  82. INSERT INTO `sys_role_permission` VALUES ('29', '1', '17');
  83. INSERT INTO `sys_role_permission` VALUES ('3', '4', '10');
  84. INSERT INTO `sys_role_permission` VALUES ('30', '1', '18');
  85. INSERT INTO `sys_role_permission` VALUES ('31', '1', '19');
  86. INSERT INTO `sys_role_permission` VALUES ('32', '1', '20');
  87. INSERT INTO `sys_role_permission` VALUES ('4', '4', '11');
  88. INSERT INTO `sys_role_permission` VALUES ('5', '4', '12');
  89. INSERT INTO `sys_role_permission` VALUES ('6', '3', '4');
  90. INSERT INTO `sys_role_permission` VALUES ('7', '3', '6');
  91. INSERT INTO `sys_role_permission` VALUES ('8', '3', '7');
  92. INSERT INTO `sys_role_permission` VALUES ('9', '3', '13');
  93. -- ----------------------------
  94. -- Table structure for sys_user
  95. -- ----------------------------
  96. DROP TABLE IF EXISTS `sys_user`;
  97. CREATE TABLE `sys_user` (
  98. `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  99. `nickname` varchar(20) DEFAULT NULL COMMENT '用户昵称',
  100. `email` varchar(128) DEFAULT NULL COMMENT '邮箱|登录帐号',
  101. `pswd` varchar(255) DEFAULT NULL COMMENT '密码',
  102. `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  103. `last_login_time` datetime DEFAULT NULL COMMENT '最后登录时间',
  104. `status` TINYINT DEFAULT '1' COMMENT '1:有效,0:禁止登录',
  105. PRIMARY KEY (`id`)
  106. ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  107. -- ----------------------------
  108. -- Records of sys_user
  109. -- ----------------------------
  110. INSERT INTO `sys_user` VALUES ('1', 'admin', 'admin@qq.com', '123456', NOW(), NOW(), '1');
  111. INSERT INTO `sys_user` VALUES ('11', 'root', '8446666@qq.com', '123456', '2016-05-26 20:50:54', '2017-02-13 15:49:04', '1');
  112. INSERT INTO `sys_user` VALUES ('12', '8446666', '8446666', 'CpievEp3tWpuK7exnZldGFzkQJDBPimEt+zG1EbUth6pmRt2pMLwSxtNJEhBRJRU', '2016-05-27 22:34:19', '2016-06-15 17:03:16', '1');
  113. INSERT INTO `sys_user` VALUES ('13', '123', '123', 'CpievEp3tWpuK7exnZldGFzkQJDBPimEt+zG1EbUth6pmRt2pMLwSxtNJEhBRJRU', '2016-05-27 22:34:19', '2016-06-15 17:03:16', '0');
  114. INSERT INTO `sys_user` VALUES ('14', 'haiqin', '123123@qq.com', 'CpievEp3tWpuK7exnZldGFzkQJDBPimEt+zG1EbUth6pmRt2pMLwSxtNJEhBRJRU', '2016-05-27 22:34:19', '2017-03-23 21:39:44', '1');
  115. -- ----------------------------
  116. -- Table structure for sys_user_role
  117. -- ----------------------------
  118. DROP TABLE IF EXISTS `sys_user_role`;
  119. CREATE TABLE `sys_user_role` (
  120. `id`  int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  121. `uid` varchar(64) DEFAULT NULL COMMENT '用户ID',
  122. `rid` varchar(64) DEFAULT NULL COMMENT '角色ID',
  123. PRIMARY KEY (`id`)
  124. ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
  125. -- ----------------------------
  126. -- Records of sys_user_role
  127. -- ----------------------------
  128. INSERT INTO `sys_user_role` VALUES ('1', '12', '4');
  129. INSERT INTO `sys_user_role` VALUES ('2', '11', '3');
  130. INSERT INTO `sys_user_role` VALUES ('3', '11', '4');
  131. INSERT INTO `sys_user_role` VALUES ('4', '1', '1');

(二)shiro配置类:

  1. package com.sun.configuration;
  2. import org.apache.log4j.Logger;
  3. import org.apache.shiro.cache.ehcache.EhCacheManager;
  4. import org.apache.shiro.spring.LifecycleBeanPostProcessor;
  5. import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
  6. import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
  7. import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
  8. import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
  9. import org.springframework.context.annotation.Bean;
  10. import org.springframework.context.annotation.Configuration;
  11. import org.springframework.transaction.annotation.EnableTransactionManagement;
  12. import java.util.LinkedHashMap;
  13. import java.util.Map;
  14. /**
  15. * Shiro 配置
  16. * Apache Shiro 核心通过 Filter 来实现,就好像SpringMvc 通过DispachServlet 来主控制一样。
  17. * 既然是使用 Filter 一般也就能猜到,是通过URL规则来进行过滤和权限校验,所以我们需要定义一系列关于URL的规则和访问权限。
  18. * Created by sun on 2017-4-2.
  19. */
  20. @Configuration
  21. @EnableTransactionManagement
  22. public class ShiroConfiguration{
  23. private final Logger logger = Logger.getLogger(ShiroConfiguration.class);
  24. /**
  25. * ShiroFilterFactoryBean 处理拦截资源文件问题。
  26. * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,因为在
  27. * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager
  28. *
  29. Filter Chain定义说明
  30. 1、一个URL可以配置多个Filter,使用逗号分隔
  31. 2、当设置多个过滤器时,全部验证通过,才视为通过
  32. 3、部分过滤器可指定参数,如perms,roles
  33. *
  34. */
  35. @Bean
  36. public EhCacheManager getEhCacheManager(){
  37. EhCacheManager ehcacheManager = new EhCacheManager();
  38. ehcacheManager.setCacheManagerConfigFile("classpath:config/ehcache-shiro.xml");
  39. return ehcacheManager;
  40. }
  41. @Bean(name = "myShiroRealm")
  42. public MyShiroRealm myShiroRealm(EhCacheManager ehCacheManager){
  43. MyShiroRealm realm = new MyShiroRealm();
  44. realm.setCacheManager(ehCacheManager);
  45. return realm;
  46. }
  47. @Bean(name = "lifecycleBeanPostProcessor")
  48. public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
  49. return new LifecycleBeanPostProcessor();
  50. }
  51. @Bean
  52. public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
  53. DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
  54. creator.setProxyTargetClass(true);
  55. return creator;
  56. }
  57. @Bean(name = "securityManager")
  58. public DefaultWebSecurityManager defaultWebSecurityManager(MyShiroRealm realm){
  59. DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
  60. //设置realm
  61. securityManager.setRealm(realm);
  62. securityManager.setCacheManager(getEhCacheManager());
  63. return securityManager;
  64. }
  65. @Bean
  66. public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager){
  67. AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
  68. advisor.setSecurityManager(securityManager);
  69. return advisor;
  70. }
  71. @Bean(name = "shiroFilter")
  72. public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
  73. ShiroFilterFactoryBean factoryBean = new MyShiroFilterFactoryBean();
  74. factoryBean.setSecurityManager(securityManager);
  75. // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
  76. factoryBean.setLoginUrl("/login");
  77. // 登录成功后要跳转的连接
  78. factoryBean.setSuccessUrl("/welcome");
  79. factoryBean.setUnauthorizedUrl("/403");
  80. loadShiroFilterChain(factoryBean);
  81. logger.info("shiro拦截器工厂类注入成功");
  82. return factoryBean;
  83. }
  84. /**
  85. * 加载ShiroFilter权限控制规则
  86. */
  87. private void loadShiroFilterChain(ShiroFilterFactoryBean factoryBean) {
  88. /**下面这些规则配置最好配置到配置文件中*/
  89. Map<String, String> filterChainMap = new LinkedHashMap<String, String>();
  90. /** authc:该过滤器下的页面必须验证后才能访问,它是Shiro内置的一个拦截器
  91. * org.apache.shiro.web.filter.authc.FormAuthenticationFilter */
  92. // anon:它对应的过滤器里面是空的,什么都没做,可以理解为不拦截
  93. //authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问
  94. filterChainMap.put("/permission/userInsert", "anon");
  95. filterChainMap.put("/error", "anon");
  96. filterChainMap.put("/tUser/insert","anon");
  97. filterChainMap.put("/**", "authc");
  98. factoryBean.setFilterChainDefinitionMap(filterChainMap);
  99. }
  100. /*1.LifecycleBeanPostProcessor,这是个DestructionAwareBeanPostProcessor的子类,负责org.apache.shiro.util.Initializable类型bean的生命周期的,初始化和销毁。主要是AuthorizingRealm类的子类,以及EhCacheManager类。
  101. 2.HashedCredentialsMatcher,这个类是为了对密码进行编码的,防止密码在数据库里明码保存,当然在登陆认证的生活,这个类也负责对form里输入的密码进行编码。
  102. 3.ShiroRealm,这是个自定义的认证类,继承自AuthorizingRealm,负责用户的认证和权限的处理,可以参考JdbcRealm的实现。
  103. 4.EhCacheManager,缓存管理,用户登陆成功后,把用户信息和权限信息缓存起来,然后每次用户请求时,放入用户的session中,如果不设置这个bean,每个请求都会查询一次数据库。
  104. 5.SecurityManager,权限管理,这个类组合了登陆,登出,权限,session的处理,是个比较重要的类。
  105. 6.ShiroFilterFactoryBean,是个factorybean,为了生成ShiroFilter。它主要保持了三项数据,securityManager,filters,filterChainDefinitionManager。
  106. 7.DefaultAdvisorAutoProxyCreator,Spring的一个bean,由Advisor决定对哪些类的方法进行AOP代理。
  107. 8.AuthorizationAttributeSourceAdvisor,shiro里实现的Advisor类,内部使用AopAllianceAnnotationsAuthorizingMethodInterceptor来拦截用以下注解的方法。*/
  108. }
  1. package com.sun.configuration;
  2. import org.apache.shiro.mgt.SecurityManager;
  3. import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
  4. import org.apache.shiro.web.filter.mgt.FilterChainManager;
  5. import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
  6. import org.apache.shiro.web.mgt.WebSecurityManager;
  7. import org.apache.shiro.web.servlet.AbstractShiroFilter;
  8. import org.springframework.beans.factory.BeanInitializationException;
  9. import javax.servlet.FilterChain;
  10. import javax.servlet.ServletException;
  11. import javax.servlet.ServletRequest;
  12. import javax.servlet.ServletResponse;
  13. import javax.servlet.http.HttpServletRequest;
  14. import java.io.IOException;
  15. import java.util.HashSet;
  16. import java.util.Set;
  17. /**
  18. * Created by sun on 2017-4-2.
  19. */
  20. public class MyShiroFilterFactoryBean extends ShiroFilterFactoryBean {
  21. // ShiroFilter将直接忽略的请求
  22. private Set<String> ignoreExt;
  23. public MyShiroFilterFactoryBean(){
  24. super();
  25. ignoreExt = new HashSet<String>();
  26. ignoreExt.add(".jpg");
  27. ignoreExt.add(".png");
  28. ignoreExt.add(".gif");
  29. ignoreExt.add(".bmp");
  30. ignoreExt.add(".js");
  31. ignoreExt.add(".css");
  32. }
  33. /**
  34. * 启动时加载
  35. */
  36. @Override
  37. protected AbstractShiroFilter createInstance() throws Exception {
  38. SecurityManager securityManager = getSecurityManager();
  39. if (securityManager == null){
  40. throw new BeanInitializationException("SecurityManager property must be set.");
  41. }
  42. if (!(securityManager instanceof WebSecurityManager)){
  43. throw new BeanInitializationException("The security manager does not implement the WebSecurityManager interface.");
  44. }
  45. PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
  46. FilterChainManager chainManager = createFilterChainManager();
  47. chainResolver.setFilterChainManager(chainManager);
  48. return new MySpringShiroFilter((WebSecurityManager)securityManager, chainResolver);
  49. }
  50. /**
  51. * 启动时加载
  52. */
  53. private class MySpringShiroFilter extends AbstractShiroFilter {
  54. public MySpringShiroFilter(
  55. WebSecurityManager securityManager, PathMatchingFilterChainResolver chainResolver) {
  56. super();
  57. if (securityManager == null){
  58. throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
  59. }
  60. setSecurityManager(securityManager);
  61. if (chainResolver != null){
  62. setFilterChainResolver(chainResolver);
  63. }
  64. }
  65. /**
  66. * 页面上传输的url先进入此方法验证
  67. */
  68. @Override
  69. protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse,
  70. FilterChain chain)
  71. throws ServletException, IOException {
  72. HttpServletRequest request = (HttpServletRequest)servletRequest;
  73. String str = request.getRequestURI().toLowerCase();
  74. boolean flag = true;
  75. int idx = 0;
  76. if ((idx = str.lastIndexOf(".")) > 0){
  77. str = str.substring(idx);
  78. if (ignoreExt.contains(str.toLowerCase())){
  79. flag = false;
  80. }
  81. }
  82. if (flag){
  83. super.doFilterInternal(servletRequest, servletResponse, chain);
  84. } else {
  85. chain.doFilter(servletRequest, servletResponse);
  86. }
  87. }
  88. }
  89. }
  1. package com.sun.configuration;
  2. import com.sun.permission.model.Role;
  3. import com.sun.permission.model.User;
  4. import com.sun.permission.service.PermissionService;
  5. import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
  6. import org.apache.commons.lang3.builder.ToStringStyle;
  7. import org.apache.log4j.Logger;
  8. import org.apache.shiro.authc.*;
  9. import org.apache.shiro.authz.AuthorizationInfo;
  10. import org.apache.shiro.authz.SimpleAuthorizationInfo;
  11. import org.apache.shiro.realm.AuthorizingRealm;
  12. import org.apache.shiro.subject.PrincipalCollection;
  13. import org.springframework.beans.factory.annotation.Autowired;
  14. import java.util.List;
  15. /**
  16. * shiro的认证最终是交给了Realm进行执行
  17. * 所以我们需要自己重新实现一个Realm,此Realm继承AuthorizingRealm
  18. * Created by sun on 2017-4-2.
  19. */
  20. public class MyShiroRealm extends AuthorizingRealm {
  21. private static final Logger logger = Logger.getLogger(MyShiroRealm.class);
  22. @Autowired
  23. private PermissionService permissionService;
  24. /**
  25. * 登录认证
  26. */
  27. @Override
  28. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
  29. //UsernamePasswordToken用于存放提交的登录信息
  30. UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
  31. logger.info("登录认证!");
  32. logger.info("验证当前Subject时获取到token为:" + ReflectionToStringBuilder.toString(token, ToStringStyle.MULTI_LINE_STYLE));
  33. User user = permissionService.findByUserEmail(token.getUsername());
  34. if (user != null){
  35. logger.info("用户: " + user.getEmail());
  36. if(user.getStatus() == 0){
  37. throw new DisabledAccountException();
  38. }
  39. // 若存在,将此用户存放到登录认证info中,无需自己做密码对比,Shiro会为我们进行密码对比校验
  40. return new SimpleAuthenticationInfo(user.getEmail(), user.getPswd(), getName());
  41. }
  42. return null;
  43. }
  44. /**
  45. * 权限认证(为当前登录的Subject授予角色和权限)
  46. *
  47. * 该方法的调用时机为需授权资源被访问时,并且每次访问需授权资源都会执行该方法中的逻辑,这表明本例中并未启用AuthorizationCache,
  48. * 如果连续访问同一个URL(比如刷新),该方法不会被重复调用,Shiro有一个时间间隔(也就是cache时间,在ehcache-shiro.xml中配置),
  49. * 超过这个时间间隔再刷新页面,该方法会被执行
  50. *
  51. * doGetAuthorizationInfo()是权限控制,
  52. * 当访问到页面的时候,使用了相应的注解或者shiro标签才会执行此方法否则不会执行,
  53. * 所以如果只是简单的身份认证没有权限的控制的话,那么这个方法可以不进行实现,直接返回null即可
  54. */
  55. @Override
  56. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
  57. String loginName = (String) super.getAvailablePrincipal(principals);
  58. User user = permissionService.findByUserEmail(loginName);
  59. logger.info("权限认证!");
  60. if (user != null){
  61. // 权限信息对象info,用来存放查出的用户的所有的角色及权限
  62. SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
  63. //用户的角色集合
  64. info.setRoles(permissionService.getRolesName(user.getId()));
  65. List<Role> roleList = permissionService.getRoleList(user.getId());
  66. for (Role role : roleList){
  67. //用户的角色对应的所有权限
  68. logger.info("角色: "+role.getName());
  69. info.addStringPermissions(permissionService.getPermissionsName(role.getId()));
  70. }
  71. return info;
  72. }
  73. // 返回null将会导致用户访问任何被拦截的请求时都会自动跳转到unauthorizedUrl指定的地址
  74. return null;
  75. }
  76. }

ehcache-shiro.xml内容:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <ehcache updateCheck="false" name="shiroCache">
  3. <!--
  4. name:缓存名称。
  5. maxElementsInMemory:缓存最大数目
  6. maxElementsOnDisk:硬盘最大缓存个数。
  7. eternal:对象是否永久有效,一但设置了,timeout将不起作用。
  8. overflowToDisk:是否保存到磁盘,当系统当机时
  9. timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
  10. timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
  11. diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
  12. diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
  13. diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
  14. memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
  15. clearOnFlush:内存数量最大时是否清除。
  16. memoryStoreEvictionPolicy:
  17. Ehcache的三种清空策略;
  18. FIFO,first in first out,这个是大家最熟的,先进先出。
  19. LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
  20. LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
  21. -->
  22. <defaultCache
  23. maxElementsInMemory="10000"
  24. eternal="false"
  25. timeToIdleSeconds="120"
  26. timeToLiveSeconds="120"
  27. overflowToDisk="false"
  28. diskPersistent="false"
  29. diskExpiryThreadIntervalSeconds="120"
  30. />
  31. <!-- 登录记录缓存锁定10分钟 -->
  32. <cache name="passwordRetryCache"
  33. maxEntriesLocalHeap="2000"
  34. eternal="false"
  35. timeToIdleSeconds="3600"
  36. timeToLiveSeconds="0"
  37. overflowToDisk="false"
  38. statistics="true">
  39. </cache>
  40. </ehcache>

登录的controller类如下:

  1. package com.sun.permission.controller;
  2. import com.sun.permission.model.User;
  3. import com.sun.permission.service.PermissionService;
  4. import com.sun.util.CommonUtils;
  5. import org.apache.commons.lang3.StringUtils;
  6. import org.apache.log4j.Logger;
  7. import org.apache.shiro.SecurityUtils;
  8. import org.apache.shiro.authc.*;
  9. import org.apache.shiro.session.Session;
  10. import org.apache.shiro.subject.Subject;
  11. import org.springframework.beans.factory.annotation.Autowired;
  12. import org.springframework.stereotype.Controller;
  13. import org.springframework.validation.BindingResult;
  14. import org.springframework.web.bind.annotation.RequestMapping;
  15. import org.springframework.web.bind.annotation.RequestMethod;
  16. import org.springframework.web.servlet.ModelAndView;
  17. import org.springframework.web.servlet.mvc.support.RedirectAttributes;
  18. import javax.validation.Valid;
  19. /**
  20. * Created by sun on 2017-4-2.
  21. */
  22. @Controller
  23. public class LoginController {
  24. private static final Logger logger = Logger.getLogger(LoginController.class);
  25. @Autowired
  26. private PermissionService permissionService;
  27. @RequestMapping(value="/login",method= RequestMethod.GET)
  28. public ModelAndView loginForm(){
  29. ModelAndView model = new ModelAndView();
  30. model.addObject("user", new User());
  31. model.setViewName("login");
  32. return model;
  33. }
  34. @RequestMapping(value="/login",method=RequestMethod.POST)
  35. public String login(@Valid User user, BindingResult bindingResult, RedirectAttributes redirectAttributes){
  36. if(bindingResult.hasErrors()){
  37. return "redirect:login";
  38. }
  39. String email = user.getEmail();
  40. if(StringUtils.isBlank(user.getEmail()) || StringUtils.isBlank(user.getPswd())){
  41. logger.info("用户名或密码为空! ");
  42. redirectAttributes.addFlashAttribute("message", "用户名或密码为空!");
  43. return "redirect:login";
  44. }
  45. //验证
  46. UsernamePasswordToken token = new UsernamePasswordToken(user.getEmail(), user.getPswd());
  47. //获取当前的Subject
  48. Subject currentUser = SecurityUtils.getSubject();
  49. try {
  50. //在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查
  51. //每个Realm都能在必要时对提交的AuthenticationTokens作出反应
  52. //所以这一步在调用login(token)方法时,它会走到MyRealm.doGetAuthenticationInfo()方法中,具体验证方式详见此方法
  53. logger.info("对用户[" + email + "]进行登录验证..验证开始");
  54. currentUser.login(token);
  55. logger.info("对用户[" + email + "]进行登录验证..验证通过");
  56. }catch(UnknownAccountException uae){
  57. logger.info("对用户[" + email + "]进行登录验证..验证未通过,未知账户");
  58. redirectAttributes.addFlashAttribute("message", "未知账户");
  59. }catch(IncorrectCredentialsException ice){
  60. logger.info("对用户[" + email + "]进行登录验证..验证未通过,错误的凭证");
  61. redirectAttributes.addFlashAttribute("message", "密码不正确");
  62. }catch(LockedAccountException lae){
  63. logger.info("对用户[" + email + "]进行登录验证..验证未通过,账户已锁定");
  64. redirectAttributes.addFlashAttribute("message", "账户已锁定");
  65. }catch(ExcessiveAttemptsException eae){
  66. logger.info("对用户[" + email + "]进行登录验证..验证未通过,错误次数大于5次,账户已锁定");
  67. redirectAttributes.addFlashAttribute("message", "用户名或密码错误次数大于5次,账户已锁定");
  68. }catch (DisabledAccountException sae){
  69. logger.info("对用户[" + email + "]进行登录验证..验证未通过,帐号已经禁止登录");
  70. redirectAttributes.addFlashAttribute("message", "帐号已经禁止登录");
  71. }catch(AuthenticationException ae){
  72. //通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景
  73. logger.info("对用户[" + email + "]进行登录验证..验证未通过,堆栈轨迹如下");
  74. ae.printStackTrace();
  75. redirectAttributes.addFlashAttribute("message", "用户名或密码不正确");
  76. }
  77. //验证是否登录成功
  78. if(currentUser.isAuthenticated()){
  79. logger.info("用户[" + email + "]登录认证通过(这里可以进行一些认证通过后的一些系统参数初始化操作)");
  80. //把当前用户放入session
  81. Session session = currentUser.getSession();
  82. User tUser = permissionService.findByUserEmail(email);
  83. session.setAttribute("currentUser",tUser);
  84. return "/welcome";
  85. }else{
  86. token.clear();
  87. return "redirect:login";
  88. }
  89. }
  90. @RequestMapping(value="/logout",method=RequestMethod.GET)
  91. public String logout(RedirectAttributes redirectAttributes ){
  92. //使用权限管理工具进行用户的退出,跳出登录,给出提示信息
  93. SecurityUtils.getSubject().logout();
  94. redirectAttributes.addFlashAttribute("message", "您已安全退出");
  95. return "redirect:login";
  96. }
  97. @RequestMapping("/403")
  98. public String unauthorizedRole(){
  99. logger.info("------没有权限-------");
  100. return "errorPermission";
  101. }
  102. }

login.jsp如下:

  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
  2. <%
  3. String path = request.getContextPath();
  4. String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
  5. %>
  6. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  7. <html>
  8. <head>
  9. <base href="<%=basePath%>">
  10. <title>Login</title>
  11. <meta http-equiv="pragma" content="no-cache">
  12. <meta http-equiv="cache-control" content="no-cache">
  13. <meta http-equiv="expires" content="0">
  14. <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
  15. <meta http-equiv="description" content="This is my page">
  16. <!--
  17. <link rel="stylesheet" type="text/css" href="styles.css">
  18. -->
  19. <script src="<%=basePath%>js/jquery-2.1.4/jquery.min.js"></script>
  20. </head>
  21. <body style="margin-left: 500px">
  22. <h1 style="margin-left: 30px">登录页面----</h1>
  23. <form action="<%=basePath%>/login" method="post">
  24. 用户名 : <input type="text" name="email" id="email"/><br>
  25. 密码: <input type="password" name="pswd" id="pswd"/><br>
  26. <input style="margin-left: 100px" type="submit" value="登录"/><input style="left: 50px" onclick="register()" type="button" value="注册"/>
  27. </form>
  28. <h1 style="color: red">${message }</h1>
  29. </body>
  30. <script type="text/javascript">
  31. function register(){
  32. location.href="<%=basePath%>permission/userInsert";
  33. }
  34. </script>
  35. </html>

welcome.jsp如下:

  1. <%--
  2. Created by IntelliJ IDEA.
  3. User: sun
  4. Date: 2017-4-2
  5. Time: 20:17
  6. To change this template use File | Settings | File Templates.
  7. --%>
  8. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  9. <%--<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>--%>
  10. <%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
  11. <html>
  12. <head>
  13. <title>欢迎!</title>
  14. </head>
  15. <body style="text-align: center">
  16. <h1>${message }</h1>
  17. <h1>用户列表--<a href="${pageContext.request.contextPath }/logout">退出登录</a></h1>
  18. 当前登录用户: <shiro:principal/><br/>
  19. <shiro:authenticated>我已登录,但未记住<br/></shiro:authenticated>
  20. <shiro:user>我已登录,或已记住<br/></shiro:user>
  21. <shiro:guest>我是访客<br/></shiro:guest>
  22. <shiro:hasAnyRoles name="manager,admin">manager or admin 角色用户登录显示此内容<br/></shiro:hasAnyRoles>
  23. <shiro:hasRole name="系统管理员">我是系统管理员<br/></shiro:hasRole>
  24. <shiro:hasRole name="会员">我是会员<br/></shiro:hasRole>
  25. <h2>权限列表</h2>
  26. <shiro:hasPermission name="权限列表">具有权限列表权限用户显示此内容<br/></shiro:hasPermission>
  27. <shiro:hasPermission name="用户列表">具有用户列表权限用户显示此内容<br/></shiro:hasPermission>
  28. <shiro:hasPermission name="在线用户">具有在线用户权限用户显示此内容<br/></shiro:hasPermission>
  29. <shiro:lacksPermission name="角色分配保存">不具有角色分配保存权限的用户显示此内容 <br/></shiro:lacksPermission>
  30. </body>
  31. </html>

启动后在页面上输入:http://localhost:8080/boot/会跳转到login登录页面:

登录后会跳转到welcome页面,该页面使用了shiro标签,会进行权限认证:

SpringBoot学习:整合shiro(身份认证和权限认证),使用EhCache缓存的更多相关文章

  1. SpringBoot整合Shiro+MD5+Salt+Redis实现认证和动态权限管理|前后端分离(下)----筑基后期

    写在前面 在上一篇文章<SpringBoot整合Shiro+MD5+Salt+Redis实现认证和动态权限管理(上)----筑基中期>当中,我们初步实现了SpringBoot整合Shiro ...

  2. SpringBoot整合Shiro+MD5+Salt+Redis实现认证和动态权限管理(上)----筑基中期

    写在前面 通过前几篇文章的学习,我们从大体上了解了shiro关于认证和授权方面的应用.在接下来的文章当中,我将通过一个demo,带领大家搭建一个SpringBoot整合Shiro的一个项目开发脚手架, ...

  3. Linux学习之用户身份与文件权限

    Linux学习之用户身份与文件权限 1 用户身份及能力 Linux系统的管理员之所以是root,并不是因为其名叫root,而是该用户身份号码数值(UID)为0. 管理员UID为0:系统的管理员用户 系 ...

  4. django身份认证、权限认证、频率校验使用及源码分析

    一. 身份认证源码分析 1.1 APIView源码的分析 APIView源码之前分析过https://www.cnblogs.com/maoruqiang/p/11135335.html,里面主要将r ...

  5. Shiro入门之二 --------基于注解方式的权限控制与Ehcache缓存

    一  基于注解方式的权限控制 首先, 在spring配置文件applicationContext.xml中配置自动代理和切面 <!-- 8配置自动代理 -->    <bean cl ...

  6. SpringBoot:整合Shiro

    目录 1.Shiro简介 1.1.什么是Shiro? 1.2.有哪些功能 1.3.Shiro架构(外部) 1.4.Shiro架构(内部) 2.HelloWorld 3.Shiro整合Spring Bo ...

  7. SpringBoot学习- 10、设计用户角色权限表

    SpringBoot学习足迹 前几节已经基本了解了SpringBoot框架常用的技术,其他的消息队列,定时器等技术暂时用不到,真正项目中如果基于微信系,阿里系开发的话,还要了解平台专用的技术知识,学习 ...

  8. 4、Shiro之IniRealm以及用户登录认证,角色认证,权限认证

    1.我们在项目test文件夹下面新建resourse文件夹并将她设置为资源文件夹: 2.在resourse文件夹下面新建user.ini文件 user.ini文件里面声明一个用户: 先写一个用户标签[ ...

  9. 7. 整合shiro,搭建粗粒度权限管理

    shiro是一个易用的权限管理框架,只需提供一个Realm即可在项目中使用,本文就将结合上一篇中搭建的权限模块.角色模块和用户模块来搭建一个粗粒度的权限管理系统,具体如下:1. 添加shiro依赖和与 ...

随机推荐

  1. KNN与SVM对比&SVM与逻辑回归的对比

    首先说一下两种学习方式: lazy learning  和  eager learning. 先说 eager learning, 这种学习方式是指在进行某种判断(例如,确定一个点的分类或者回归中确定 ...

  2. 【WIN10】Segoe MDL2 Assets

    APP下載地址:https://www.microsoft.com/store/apps/9nblggh5k2hf 最近使用文本圖標Segoe MDL2 Assets時,使用字符映射表看,那個圖標真的 ...

  3. android 地图

    ========= Y:\AMap_Android_API_3DMap_Demo\android_studio\AMap3DDemo>keytool -v -list -keystore C:\ ...

  4. android stuidio 导入项目问题。

    避免重新下载. === === === 改成自己对应的. ===== Gradle sync failed: Could not find method android() for arguments ...

  5. android activity 启动模式

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha 1,标准的, 2,单个 顶部 3,单个 任务 4,单个 实例 标准的 就是 每启动一次这 ...

  6. MikroTik RouterOS 5.x破解工具HunterTik

    HunterTik目前网络上流传的版本大概就两个版本2.3.1和2.3.1.1,其实效果基本一致,都是不能破解高版本的RouterOS,比如6.6以后的版本就不行了. 一.安装: 一路回车! 二.可以 ...

  7. 用css解决table文字溢出控制td显示字数(转)

    场景: 最左边这栏我不行让他换行,怎么办呢? 下面是解决办法: table{ width:100px; table-layout:fixed;/* 只有定义了表格的布局算法为fixed,下面td的定义 ...

  8. C#中执行Dos命令

    //dosCommand Dos命令语句 public string Execute(string dosCommand) { ); } /// <summary> /// 执行DOS命令 ...

  9. 基于SmartThreadPool线程池技术实现多任务批量处理

    一.多线程技术应用场景介绍 本期同样带给大家分享的是阿笨在实际工作中遇到的真实业务场景,请跟随阿笨的视角去如何采用基于开源组件SmartThreadPool线程池技术实现多任务批量处理.在工作中您是否 ...

  10. 报错:TargetException, 非静态方法需要一个目标

    如果实例为null,调用实例方法会报如上错. 解决办法: 检查实例是否为null,考虑什么情况下实例为null,然后排除实例为null的情况.