shiro实现授权-注解方式

2019-10-21  本文已影响0人  ssttIsme

一个用户对应多个角色
一个角色对应多个权限
本案例的权限体现在菜单对应的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);
    }
}

上一篇下一篇

猜你喜欢

热点阅读