• SpringBoot学习:整合shiro(身份认证和权限认证),使用EhCache缓存(转)


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

    (二)shiro配置类:

    1. package com.sun.configuration;  
    2.   
    3. import org.apache.log4j.Logger;  
    4. import org.apache.shiro.cache.ehcache.EhCacheManager;  
    5. import org.apache.shiro.spring.LifecycleBeanPostProcessor;  
    6. import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;  
    7. import org.apache.shiro.spring.web.ShiroFilterFactoryBean;  
    8. import org.apache.shiro.web.mgt.DefaultWebSecurityManager;  
    9. import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;  
    10. import org.springframework.context.annotation.Bean;  
    11. import org.springframework.context.annotation.Configuration;  
    12. import org.springframework.transaction.annotation.EnableTransactionManagement;  
    13.   
    14. import java.util.LinkedHashMap;  
    15. import java.util.Map;  
    16.   
    17. /**  
    18.  * Shiro 配置  
    19.  * Apache Shiro 核心通过 Filter 来实现,就好像SpringMvc 通过DispachServlet 来主控制一样。  
    20.  * 既然是使用 Filter 一般也就能猜到,是通过URL规则来进行过滤和权限校验,所以我们需要定义一系列关于URL的规则和访问权限。  
    21.  * Created by sun on 2017-4-2.  
    22.  */  
    23. @Configuration  
    24. @EnableTransactionManagement  
    25. public class ShiroConfiguration{  
    26.   
    27.     private final Logger logger = Logger.getLogger(ShiroConfiguration.class);  
    28.   
    29.     /**  
    30.      * ShiroFilterFactoryBean 处理拦截资源文件问题。  
    31.      * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,因为在  
    32.      * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager  
    33.      *  
    34.      Filter Chain定义说明  
    35.      1、一个URL可以配置多个Filter,使用逗号分隔  
    36.      2、当设置多个过滤器时,全部验证通过,才视为通过  
    37.      3、部分过滤器可指定参数,如perms,roles  
    38.      *  
    39.      */  
    40.     @Bean  
    41.     public EhCacheManager getEhCacheManager(){  
    42.         EhCacheManager ehcacheManager = new EhCacheManager();  
    43.         ehcacheManager.setCacheManagerConfigFile("classpath:config/ehcache-shiro.xml");  
    44.         return ehcacheManager;  
    45.     }  
    46.   
    47.     @Bean(name = "myShiroRealm")  
    48.     public MyShiroRealm myShiroRealm(EhCacheManager ehCacheManager){  
    49.         MyShiroRealm realm = new MyShiroRealm();  
    50.         realm.setCacheManager(ehCacheManager);  
    51.         return realm;  
    52.     }  
    53.   
    54.     @Bean(name = "lifecycleBeanPostProcessor")  
    55.     public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){  
    56.         return new LifecycleBeanPostProcessor();  
    57.     }  
    58.   
    59.     @Bean  
    60.     public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){  
    61.         DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();  
    62.         creator.setProxyTargetClass(true);  
    63.         return creator;  
    64.     }  
    65.   
    66.     @Bean(name = "securityManager")  
    67.     public DefaultWebSecurityManager defaultWebSecurityManager(MyShiroRealm realm){  
    68.         DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();  
    69.         //设置realm  
    70.         securityManager.setRealm(realm);  
    71.         securityManager.setCacheManager(getEhCacheManager());  
    72.         return securityManager;  
    73.     }  
    74.   
    75.     @Bean  
    76.     public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager){  
    77.         AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();  
    78.         advisor.setSecurityManager(securityManager);  
    79.         return advisor;  
    80.     }  
    81.   
    82.     @Bean(name = "shiroFilter")  
    83.     public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager){  
    84.         ShiroFilterFactoryBean factoryBean = new MyShiroFilterFactoryBean();  
    85.         factoryBean.setSecurityManager(securityManager);  
    86.         // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面  
    87.         factoryBean.setLoginUrl("/login");  
    88.         // 登录成功后要跳转的连接  
    89.         factoryBean.setSuccessUrl("/welcome");  
    90.         factoryBean.setUnauthorizedUrl("/403");  
    91.         loadShiroFilterChain(factoryBean);  
    92.         logger.info("shiro拦截器工厂类注入成功");  
    93.         return factoryBean;  
    94.     }  
    95.   
    96.     /**  
    97.      * 加载ShiroFilter权限控制规则  
    98.      */  
    99.     private void loadShiroFilterChain(ShiroFilterFactoryBean factoryBean) {  
    100.         /**下面这些规则配置最好配置到配置文件中*/  
    101.         Map<String, String> filterChainMap = new LinkedHashMap<String, String>();  
    102.         /** authc:该过滤器下的页面必须验证后才能访问,它是Shiro内置的一个拦截器  
    103.          * org.apache.shiro.web.filter.authc.FormAuthenticationFilter */  
    104.         // anon:它对应的过滤器里面是空的,什么都没做,可以理解为不拦截  
    105.         //authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问  
    106.         filterChainMap.put("/permission/userInsert", "anon");  
    107.         filterChainMap.put("/error", "anon");  
    108.         filterChainMap.put("/tUser/insert","anon");  
    109.         filterChainMap.put("/**", "authc");  
    110.   
    111.         factoryBean.setFilterChainDefinitionMap(filterChainMap);  
    112.     }  
    113.   
    114.     /*1.LifecycleBeanPostProcessor,这是个DestructionAwareBeanPostProcessor的子类,负责org.apache.shiro.util.Initializable类型bean的生命周期的,初始化和销毁。主要是AuthorizingRealm类的子类,以及EhCacheManager类。  
    115.     2.HashedCredentialsMatcher,这个类是为了对密码进行编码的,防止密码在数据库里明码保存,当然在登陆认证的生活,这个类也负责对form里输入的密码进行编码。  
    116.     3.ShiroRealm,这是个自定义的认证类,继承自AuthorizingRealm,负责用户的认证和权限的处理,可以参考JdbcRealm的实现。  
    117.     4.EhCacheManager,缓存管理,用户登陆成功后,把用户信息和权限信息缓存起来,然后每次用户请求时,放入用户的session中,如果不设置这个bean,每个请求都会查询一次数据库。  
    118.     5.SecurityManager,权限管理,这个类组合了登陆,登出,权限,session的处理,是个比较重要的类。  
    119.     6.ShiroFilterFactoryBean,是个factorybean,为了生成ShiroFilter。它主要保持了三项数据,securityManager,filters,filterChainDefinitionManager。  
    120.     7.DefaultAdvisorAutoProxyCreator,Spring的一个bean,由Advisor决定对哪些类的方法进行AOP代理。  
    121.     8.AuthorizationAttributeSourceAdvisor,shiro里实现的Advisor类,内部使用AopAllianceAnnotationsAuthorizingMethodInterceptor来拦截用以下注解的方法。*/  
    122.   
    123. }  

    1. package com.sun.configuration;  
    2.   
    3. import org.apache.shiro.mgt.SecurityManager;  
    4. import org.apache.shiro.spring.web.ShiroFilterFactoryBean;  
    5. import org.apache.shiro.web.filter.mgt.FilterChainManager;  
    6. import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;  
    7. import org.apache.shiro.web.mgt.WebSecurityManager;  
    8. import org.apache.shiro.web.servlet.AbstractShiroFilter;  
    9. import org.springframework.beans.factory.BeanInitializationException;  
    10.   
    11. import javax.servlet.FilterChain;  
    12. import javax.servlet.ServletException;  
    13. import javax.servlet.ServletRequest;  
    14. import javax.servlet.ServletResponse;  
    15. import javax.servlet.http.HttpServletRequest;  
    16. import java.io.IOException;  
    17. import java.util.HashSet;  
    18. import java.util.Set;  
    19.   
    20. /  
    21.   Created by sun on 2017-4-2.  
    22.  /  
    23. public class MyShiroFilterFactoryBean extends ShiroFilterFactoryBean {  
    24.     // ShiroFilter将直接忽略的请求  
    25.     private Set<String> ignoreExt;  
    26.   
    27.     public MyShiroFilterFactoryBean(){  
    28.         super();  
    29.         ignoreExt = new HashSet<String>();  
    30.         ignoreExt.add(".jpg");  
    31.         ignoreExt.add(".png");  
    32.         ignoreExt.add(".gif");  
    33.         ignoreExt.add(".bmp");  
    34.         ignoreExt.add(".js");  
    35.         ignoreExt.add(".css");  
    36.     }  
    37.     /  
    38.       启动时加载  
    39.      /  
    40.     @Override  
    41.     protected AbstractShiroFilter createInstance() throws Exception {  
    42.         SecurityManager securityManager = getSecurityManager();  
    43.         if (securityManager  null){  
    44.             throw new BeanInitializationException("SecurityManager property must be set.");  
    45.         }  
    46.   
    47.         if (!(securityManager instanceof WebSecurityManager)){  
    48.             throw new BeanInitializationException("The security manager does not implement the WebSecurityManager interface.");  
    49.         }  
    50.   
    51.         PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();  
    52.         FilterChainManager chainManager = createFilterChainManager();  
    53.         chainResolver.setFilterChainManager(chainManager);  
    54.         return new MySpringShiroFilter((WebSecurityManager)securityManager, chainResolver);  
    55.     }  
    56.   
    57.     /**  
    58.       启动时加载  
    59.      /  
    60.     private class MySpringShiroFilter extends AbstractShiroFilter {  
    61.         public MySpringShiroFilter(  
    62.                 WebSecurityManager securityManager, PathMatchingFilterChainResolver chainResolver) {  
    63.             super();  
    64.             if (securityManager  null){  
    65.                 throw new IllegalArgumentException("WebSecurityManager property cannot be null.");  
    66.             }  
    67.             setSecurityManager(securityManager);  
    68.             if (chainResolver != null){  
    69.                 setFilterChainResolver(chainResolver);  
    70.             }  
    71.         }  
    72.         /**  
    73.           页面上传输的url先进入此方法验证  
    74.          /  
    75.         @Override  
    76.         protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse,  
    77.                                         FilterChain chain)  
    78.                 throws ServletException, IOException {  
    79.             HttpServletRequest request = (HttpServletRequest)servletRequest;  
    80.             String str = request.getRequestURI().toLowerCase();  
    81.             boolean flag = true;  
    82.             int idx = 0;  
    83.             if ((idx = str.lastIndexOf(".")) > 0){  
    84.                 str = str.substring(idx);  
    85.                 if (ignoreExt.contains(str.toLowerCase())){  
    86.                     flag = false;  
    87.                 }  
    88.             }  
    89.             if (flag){  
    90.                 super.doFilterInternal(servletRequest, servletResponse, chain);  
    91.             } else {  
    92.                 chain.doFilter(servletRequest, servletResponse);  
    93.             }  
    94.         }  
    95.     }  
    96. }  

    1. package com.sun.configuration;  
    2.   
    3. import com.sun.permission.model.Role;  
    4. import com.sun.permission.model.User;  
    5. import com.sun.permission.service.PermissionService;  
    6. import org.apache.commons.lang3.builder.ReflectionToStringBuilder;  
    7. import org.apache.commons.lang3.builder.ToStringStyle;  
    8. import org.apache.log4j.Logger;  
    9. import org.apache.shiro.authc.;  
    10. import org.apache.shiro.authz.AuthorizationInfo;  
    11. import org.apache.shiro.authz.SimpleAuthorizationInfo;  
    12. import org.apache.shiro.realm.AuthorizingRealm;  
    13. import org.apache.shiro.subject.PrincipalCollection;  
    14. import org.springframework.beans.factory.annotation.Autowired;  
    15.   
    16. import java.util.List;  
    17.   
    18. /  
    19.   shiro的认证最终是交给了Realm进行执行  
    20.   所以我们需要自己重新实现一个Realm,此Realm继承AuthorizingRealm  
    21.   Created by sun on 2017-4-2.  
    22.  /  
    23. public class MyShiroRealm extends AuthorizingRealm {  
    24.   
    25.     private static final Logger logger = Logger.getLogger(MyShiroRealm.class);  
    26.     @Autowired  
    27.     private PermissionService permissionService;  
    28.     /  
    29.       登录认证  
    30.      /  
    31.     @Override  
    32.     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {  
    33.         //UsernamePasswordToken用于存放提交的登录信息  
    34.         UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;  
    35.         logger.info("登录认证!");  
    36.         logger.info("验证当前Subject时获取到token为:" + ReflectionToStringBuilder.toString(token, ToStringStyle.MULTI_LINE_STYLE));  
    37.         User user = permissionService.findByUserEmail(token.getUsername());  
    38.         if (user != null){  
    39.             logger.info("用户: " + user.getEmail());  
    40.             if(user.getStatus() == 0){  
    41.                 throw new DisabledAccountException();  
    42.             }  
    43.             // 若存在,将此用户存放到登录认证info中,无需自己做密码对比,Shiro会为我们进行密码对比校验  
    44.             return new SimpleAuthenticationInfo(user.getEmail(), user.getPswd(), getName());  
    45.         }  
    46.         return null;  
    47.     }  
    48.   
    49.     /**  
    50.       权限认证(为当前登录的Subject授予角色和权限)  
    51.        
    52.       该方法的调用时机为需授权资源被访问时,并且每次访问需授权资源都会执行该方法中的逻辑,这表明本例中并未启用AuthorizationCache,  
    53.       如果连续访问同一个URL(比如刷新),该方法不会被重复调用,Shiro有一个时间间隔(也就是cache时间,在ehcache-shiro.xml中配置),  
    54.       超过这个时间间隔再刷新页面,该方法会被执行  
    55.        
    56.       doGetAuthorizationInfo()是权限控制,  
    57.       当访问到页面的时候,使用了相应的注解或者shiro标签才会执行此方法否则不会执行,  
    58.       所以如果只是简单的身份认证没有权限的控制的话,那么这个方法可以不进行实现,直接返回null即可  
    59.      /  
    60.     @Override  
    61.     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {  
    62.         String loginName = (String) super.getAvailablePrincipal(principals);  
    63.         User user = permissionService.findByUserEmail(loginName);  
    64.         logger.info("权限认证!");  
    65.         if (user != null){  
    66.             // 权限信息对象info,用来存放查出的用户的所有的角色及权限  
    67.             SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();  
    68.             //用户的角色集合  
    69.             info.setRoles(permissionService.getRolesName(user.getId()));  
    70.             List<Role> roleList = permissionService.getRoleList(user.getId());  
    71.             for (Role role : roleList){  
    72.                 //用户的角色对应的所有权限  
    73.                 logger.info("角色: "+role.getName());  
    74.                 info.addStringPermissions(permissionService.getPermissionsName(role.getId()));  
    75.             }  
    76.             return info;  
    77.         }  
    78.         // 返回null将会导致用户访问任何被拦截的请求时都会自动跳转到unauthorizedUrl指定的地址  
    79.         return null;  
    80.     }  
    81. }  

import com.sun.permission.model.Role;
import com.sun.permission.model.User;
import com.sun.permission.service.PermissionService;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.log4j.Logger;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

/**

  • shiro的认证最终是交给了Realm进行执行

  • 所以我们需要自己重新实现一个Realm,此Realm继承AuthorizingRealm

  • Created by sun on 2017-4-2.
    */
    public class MyShiroRealm extends AuthorizingRealm {

    private static final Logger logger = Logger.getLogger(MyShiroRealm.class);
    @Autowired
    private PermissionService permissionService;
    /**

    • 登录认证
      */
      @Override
      protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
      //UsernamePasswordToken用于存放提交的登录信息
      UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
      logger.info("登录认证!");
      logger.info("验证当前Subject时获取到token为:" + ReflectionToStringBuilder.toString(token, ToStringStyle.MULTI_LINE_STYLE));
      User user = permissionService.findByUserEmail(token.getUsername());
      if (user != null){
      logger.info("用户: " + user.getEmail());
      if(user.getStatus() == 0){
      throw new DisabledAccountException();
      }
      // 若存在,将此用户存放到登录认证info中,无需自己做密码对比,Shiro会为我们进行密码对比校验
      return new SimpleAuthenticationInfo(user.getEmail(), user.getPswd(), getName());
      }
      return null;
      }

    /**

    • 权限认证(为当前登录的Subject授予角色和权限)
    • 该方法的调用时机为需授权资源被访问时,并且每次访问需授权资源都会执行该方法中的逻辑,这表明本例中并未启用AuthorizationCache,
    • 如果连续访问同一个URL(比如刷新),该方法不会被重复调用,Shiro有一个时间间隔(也就是cache时间,在ehcache-shiro.xml中配置),
    • 超过这个时间间隔再刷新页面,该方法会被执行
    • doGetAuthorizationInfo()是权限控制,
    • 当访问到页面的时候,使用了相应的注解或者shiro标签才会执行此方法否则不会执行,
    • 所以如果只是简单的身份认证没有权限的控制的话,那么这个方法可以不进行实现,直接返回null即可
      */
      @Override
      protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
      String loginName = (String) super.getAvailablePrincipal(principals);
      User user = permissionService.findByUserEmail(loginName);
      logger.info("权限认证!");
      if (user != null){
      // 权限信息对象info,用来存放查出的用户的所有的角色及权限
      SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
      //用户的角色集合
      info.setRoles(permissionService.getRolesName(user.getId()));
      List<Role> roleList = permissionService.getRoleList(user.getId());
      for (Role role : roleList){
      //用户的角色对应的所有权限
      logger.info("角色: "+role.getName());
      info.addStringPermissions(permissionService.getPermissionsName(role.getId()));
      }
      return info;
      }
      // 返回null将会导致用户访问任何被拦截的请求时都会自动跳转到unauthorizedUrl指定的地址
      return null;
      }
      }

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

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


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



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






原文地址:http://blog.csdn.net/aqsunkai/article/details/69757017

  • 相关阅读:
    字节
    服务器每个网站占用资源
    in exists 条件查询
    NUnit2.0详细使用方法
    敏捷方法之极限编程(XP)和 Scrum区别
    学习内容及计划
    关于查看网页源文件不显示源代码(打开的是桌面文件夹)的问题
    用JS取float型 小数点 后两位
    [转]什么是CMMI?
    六月新版微软一站式示例代码库发布 新增20个Windows示例代码
  • 原文地址:https://www.cnblogs.com/jpfss/p/8336935.html
  • Copyright © 2020-2023  润新知