美文网首页
shiro实现授权-注解方式

shiro实现授权-注解方式

作者: ssttIsme | 来源:发表于2019-10-21 17:48 被阅读0次

    一个用户对应多个角色
    一个角色对应多个权限
    本案例的权限体现在菜单对应的permission(授权标识)上,权限检查会检查对应菜单的permission(授权标识)

    menu
    roles
    roles_menus
    sys_users
    sys_users_roles
    USE `shop`;
    
    /*Table structure for table `menus` */
    
    DROP TABLE IF EXISTS `menus`;
    
    CREATE TABLE `menus` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(50) DEFAULT NULL,
      `url` varchar(200) DEFAULT NULL,
      `type` int(11) DEFAULT NULL,
      `sort` int(11) DEFAULT NULL,
      `note` varchar(100) DEFAULT NULL,
      `parentId` int(11) DEFAULT NULL,
      `permission` varchar(500) DEFAULT NULL,
      `created` datetime DEFAULT NULL,
      `updated` datetime DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
    
    /*Data for the table `menus` */
    
    insert  into `menus`(`id`,`name`,`url`,`type`,`sort`,`note`,`parentId`,`permission`,`created`,`updated`) values (1,'系统管理','',1,1,'系统管理...',0,'sys:view','2019-09-15 10:17:31','2019-09-21 21:14:27'),(2,'角色管理','role/list',1,2,'角色管理...',1,'sys:role:view','2019-09-15 10:18:04','2019-10-13 23:56:06'),(3,'用户管理','user/list',1,3,'用户管理...',1,'sys:user:view','2019-09-21 19:49:36','2019-10-13 23:56:42'),(4,'角色添加','role/saveObject',2,1,'角色添加',2,'sys:role:create','2019-10-13 23:55:45','2019-10-13 23:59:10'),(5,'角色修改','role/updateObject',2,2,'角色修改',2,'sys:role:update','2019-10-13 23:58:28','2019-10-20 14:23:27');
    
    /*Table structure for table `roles` */
    
    DROP TABLE IF EXISTS `roles`;
    
    CREATE TABLE `roles` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `name` varchar(100) DEFAULT NULL,
      `note` varchar(500) DEFAULT NULL,
      `created` datetime DEFAULT NULL,
      `updated` datetime DEFAULT NULL,
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=53 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;
    
    /*Data for the table `roles` */
    
    insert  into `roles`(`id`,`name`,`note`,`created`,`updated`) values (51,'admin','管理员','2019-09-04 22:15:35','2019-09-04 22:15:35'),(52,'normal','普通用户','2019-09-04 22:15:47','2019-10-20 14:41:46');
    
    /*Table structure for table `roles_menus` */
    
    DROP TABLE IF EXISTS `roles_menus`;
    
    CREATE TABLE `roles_menus` (
      `role_id` int(11) NOT NULL DEFAULT '0',
      `menu_id` int(11) NOT NULL DEFAULT '0',
      PRIMARY KEY (`role_id`,`menu_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    /*Data for the table `roles_menus` */
    
    insert  into `roles_menus`(`role_id`,`menu_id`) values (51,1),(51,2),(51,3),(51,4),(51,5);
    
    /*Table structure for table `sys_users`   密码均为123 */
    
    DROP TABLE IF EXISTS `sys_users`;
    
    CREATE TABLE `sys_users` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `username` varchar(50) NOT NULL,
      `password` varchar(100) DEFAULT NULL,
      `salt` varchar(50) DEFAULT NULL,
      `email` varchar(100) DEFAULT NULL,
      `mobile` varchar(100) DEFAULT NULL,
      `valid` tinyint(4) DEFAULT NULL,
      `created` datetime DEFAULT NULL,
      `updated` datetime DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;
    
    /*Data for the table `sys_users` */
    
    insert  into `sys_users`(`id`,`username`,`password`,`salt`,`email`,`mobile`,`valid`,`created`,`updated`) values (1,'zhangsan','b89a1238af16bf30c5cc572f08c60e82','0ca5b031-1cc5-40e8-94b6-e577e2b78f52','a@qq.com','15300018956',1,'2019-09-04 00:03:37','2019-10-13 23:11:56'),(2,'lisi','29e95d825f49af77e90449b62effaaf8','66d7c441-2b3e-4343-8c9e-054e9e580dfe','b@qq.com','15300018923',1,'2019-09-04 00:03:41','2019-10-13 23:11:37'),(3,'test','269925a0fcd19ee9749715d66538cb37','08c01cbc-773a-4dda-a83d-6db7ea0f695c','2@qq.com','15300018569',1,'2019-09-04 23:12:58','2019-10-13 23:11:47'),(4,'alpcer','e4c943a82b9752a21c01501db29998bb','377cc328-88ce-4534-b4a0-ff2914ab6155','a@qq.com','15300028652',1,'2019-09-04 23:31:56','2019-10-13 23:12:41'),(5,'mjp','d503597b4f73c4c25eeb15f5d44c8411','5dcc5134-793e-4765-8383-fe4b1d157cba','b@163.com','15300018562',1,'2019-09-06 23:06:15','2019-10-13 23:11:17'),(6,'wx','420a1a4ae0f5565d27004af508ee270d','b16daf59-cbc5-48c6-a91f-2a5f481c90bb','b@163.com','15300018562',1,'2019-09-06 23:07:19','2019-10-13 22:52:20'),(7,'ww','52a1df05ff427c0007791b978d2b9981','025da5d4-9a4b-4ea1-aed4-cca185fab4f9','b@163.com','15300018562',1,'2019-09-06 23:09:37','2019-10-13 23:07:04'),(8,'sy_test','9ec076534b0039e1f4bd8637c2d8a69e','c95f38ce-9ce4-4775-9511-558bdf0b7475','b@163.com','15300018562',1,'2019-09-06 23:12:13','2019-10-13 23:10:54'),(9,'alice','7fbc8843e04e00f80f2108de071e7a3a','420557e2-d1c0-4ac4-b8fe-2e7dfb969211','b@qq.com','15300018923',1,'2019-09-13 20:56:53','2019-10-13 23:10:47'),(10,'dom','89f7cae0dd7727abb5a99c3a9a405ceb','8a56660a-c1d3-46c4-9514-f3317484c4fc','eeeb@163.com','15300018562',1,'2019-09-13 20:57:28','2019-10-13 23:10:38'),(11,'John','6c1574fbb2ffe9da7147b3540454b1da','21b1f675-a36e-41d8-b021-23ec8925b72c','b@163.com','15300018562',1,'2019-09-13 20:58:07','2019-10-13 23:10:30'),(12,'wangnan','04f3f1cce625d30b37ee39911c10c88a','be21abb3-dfde-44d4-80bf-4d9adfafee21','1223@qq.com','66666',1,'2019-09-13 21:02:14','2019-10-13 23:08:54'),(13,'David','05a629f9a12a115384c2f2ea91f6470e','17520f66-4f75-48f1-b9a7-843e7a2df944','b@163.com','15300018562',1,'2019-09-13 21:03:21','2019-10-13 23:08:46'),(14,'bell','c78c8465d7ca0e12a224d4ea11cc6845','dc56cbde-694e-45eb-af4b-f9deba147a99','111@qq.com','110',1,'2019-09-13 21:49:33','2019-10-13 23:08:36'),(15,'wangbaoqiang','841dc36cb55c56bb0d690b87035adafe','4a0dd0d4-8757-4c37-9194-15d7d3bd858c','wang@qq.com','15300018952',1,'2019-10-06 12:58:22','2019-10-13 23:10:11'),(16,'zhanglei','6efcf4e9dec2eb42af7479985f6745c2','9437c6bb-9c12-403b-80b9-e05611fc40ba','4@qq.com','2',1,'2019-10-06 12:59:47','2019-10-20 14:28:56');
    
    /*Table structure for table `sys_users_roles` */
    
    DROP TABLE IF EXISTS `sys_users_roles`;
    
    CREATE TABLE `sys_users_roles` (
      `user_id` int(11) NOT NULL DEFAULT '0',
      `role_id` int(11) NOT NULL DEFAULT '0',
      PRIMARY KEY (`user_id`,`role_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    /*Data for the table `sys_users_roles` */
    
    insert  into `sys_users_roles`(`user_id`,`role_id`) values (1,51),(2,52),(3,51),(4,52),(5,52),(6,52),(7,51),(7,52),(8,52),(9,51),(9,52),(10,51),(11,51),(11,52),(12,51),(13,52),(14,51),(14,52),(15,51),(16,51);
    

    pom.xml

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

    核心代码-权限有可能重复,所以放到set集合,放之前先排除空串

    /**
         * 授权检测
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            SysUser user=(SysUser) SecurityUtils.getSubject().getSession().getAttribute("user");
            //根据用户信息获取用户权限
            List<String> list=sysUserDao.findUserPermissions(user.getId());
            //去除重复的权限
            HashSet<String> set = new HashSet<>();
            for(String p:list){
                if(!StringUtils.isEmpty(p)){
                    set.add(p);
                }
            }
            System.out.println("permissions= "+set);
            //封装用户权限
            SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
            info.setStringPermissions(set);
            return info;
        }
    
    package com.school.service.realm;
    
    import java.util.HashSet;
    import java.util.List;
    
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.AuthenticationInfo;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authc.SimpleAuthenticationInfo;
    import org.apache.shiro.authc.UsernamePasswordToken;
    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.apache.shiro.util.ByteSource;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import com.alibaba.druid.util.StringUtils;
    import com.school.dao.SysUserDao;
    import com.school.entity.SysUser;
    /**
     *通过realm这个领域对象对认证领域和授权领域信息进行检测
     */
    @Service
    public class ShiroUserRealm extends AuthorizingRealm {
        @Autowired
        SysUserDao sysUserDao;
    
        /**
         * 授权检测
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            SysUser user=(SysUser) SecurityUtils.getSubject().getSession().getAttribute("user");
            //根据用户信息获取用户权限
            List<String> list=sysUserDao.findUserPermissions(user.getId());
            //去除重复的权限
            HashSet<String> set = new HashSet<>();
            for(String p:list){
                if(!StringUtils.isEmpty(p)){
                    set.add(p);
                }
            }
            System.out.println("permissions= "+set);
            //封装用户权限
            SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
            info.setStringPermissions(set);
            return info;
        }
    
        /**
         * 认证检测
         * 检测用户身份是否存在,密码是否正确
         * subject.login(token)->
         * SecurityManager->
         * Authentication->
         * ShiroUserRealm->
         * ShiroUserRealm.Authentication
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            UsernamePasswordToken upToken=(UsernamePasswordToken)token;
            //获取用户名
            String username = upToken.getUsername();
            //根据用户名查找用户对象
            SysUser user = sysUserDao.findObjectByUserName(username);
            //初始化SimpleAuthenticationInfo对象
            ByteSource saltSource = ByteSource.Util.bytes(user.getSalt().getBytes());
            SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(
                    user.getUsername(),//用户身份
                    user.getPassword(), //已加密 的密码
                    saltSource,//盐值对应的byteSource
                    getName());//realm的名字
            //存储用户信息
            SecurityUtils.getSubject().getSession().setAttribute("user", user);
            return info;
        }
    
    }
    
    

    web.xml

        <!--配置SpringMVC前端控制器 -->
        <!--配置shiro -->
        <filter>
            <filter-name>shiroFilter</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
            <init-param>
                <param-name>targetBeanName</param-name>
                <param-value>shiroFilter</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>shiroFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    

    shiro-configs.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc"
        xmlns:util="http://www.springframework.org/schema/util" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
        xsi:schemaLocation="  
           http://www.springframework.org/schema/beans   
           http://www.springframework.org/schema/beans/spring-beans-4.3.xsd  
           http://www.springframework.org/schema/mvc   
           http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd   
           http://www.springframework.org/schema/tx   
           http://www.springframework.org/schema/tx/spring-tx-4.3.xsd   
           http://www.springframework.org/schema/aop 
           http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
           http://www.springframework.org/schema/util 
           http://www.springframework.org/schema/util/spring-util-4.3.xsd
           http://www.springframework.org/schema/data/jpa 
           http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-4.3.xsd">
        <bean id="userRealm" class="com.school.service.realm.ShiroUserRealm">
            <property name="credentialsMatcher">
                <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                    <property name="hashAlgorithmName" value="MD5" />
                </bean>
            </property>
        </bean>
        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <property name="loginUrl"  value="/login"/>
            <property name="securityManager" ref="securityManager"></property>
            <property name="filterChainDefinitions">
                <value>
                    /bootstrap/**=anon
                    /build/**=anon
                    /dist/**=anon
                    /document/**=anon
                    /font-awesome/**=anon
                    /ionicons/**=anon
                    /layer/**=anon
                    /pages/**=anon
                    /plugins/**=anon
                    /treegrid/**=anon
                    /ztree/**=anon
                    /doLogin=anon
                    /doLogout=logout
                    /**=authc
                </value>
            </property>
        </bean>
        <!-- 配置Shiro中的SecurityManager -->
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="realm" ref="userRealm"></property>
        </bean>
        
        <!-- 配置bean对象的生命周期管理 (可以自动地调用配置在springIoc容器中shiro-bean的生命周期方法)-->
        <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
        <!-- 启用shiro注解权限检查 -->
        <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
        depends-on="lifecycleBeanPostProcessor"/>
        <!-- 配置授权属性 -->
        <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
            <property name="SecurityManager" ref="securityManager"></property>
        </bean>
    </beans>
    

    这几项就是权限检查的配置

        <!-- 配置bean对象的生命周期管理 (可以自动地调用配置在springIoc容器中shiro-bean的生命周期方法)-->
        <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
        <!-- 启用shiro注解权限检查 -->
        <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
        depends-on="lifecycleBeanPostProcessor"/>
        <!-- 配置授权属性 -->
        <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
            <property name="SecurityManager" ref="securityManager"></property>
        </bean>
    </beans>
    

    在需要做权限检查的地方加注解,比如 @RequiresPermissions("sys:role:update")
    在用户进行角色更新的时候,进行权限检查

        @RequiresPermissions("sys:role:update")
        @RequestMapping("/updateObject")
        @ResponseBody
        public JsonResult updateObject(Role entity){
            roleService.updateObject(entity); 
            return new JsonResult(1,"update ok");
        }
    

    因为没有权限会抛异常,所以在异常处理类可做如下操作

    else if(e instanceof UnauthorizedException){
                msg="权限不足!";
            }
    

    完整代码如下

    package com.school.common.controller;
    
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.IncorrectCredentialsException;
    import org.apache.shiro.authz.UnauthorizedException;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import com.school.common.exception.ServiceException;
    import com.school.common.vo.JsonResult;
    
    @ControllerAdvice
    public class ControllerExceptionHandler {
        /**
         * @ExceptionHandler 用于描述这个方法能够处理的异常
         * @param e
         */
        @ExceptionHandler(ServiceException.class)
        @ResponseBody
        public JsonResult handleServiceException(ServiceException e){
            String msg=e.getMessage();
            System.out.println(msg);
            return new JsonResult(0,msg);
        }
    
        @ExceptionHandler(RuntimeException.class)
        @ResponseBody
        public JsonResult handleServiceException(RuntimeException e){
            String msg=e.getMessage();
            if(e instanceof IncorrectCredentialsException){
                msg="密码不正确!";
            }
            else if(e instanceof AuthenticationException){
                msg="用户名不存在!";
            }
            else if(e instanceof UnauthorizedException){
                msg="权限不足!";
            }
            System.out.println(msg);
            return new JsonResult(0,msg);
        }
    }
    
    

    相关文章

      网友评论

          本文标题:shiro实现授权-注解方式

          本文链接:https://www.haomeiwen.com/subject/wotxvctx.html