JAVA项目实战-shiro框架使用(一)

shiro主要处理项目中用户模块、角色模块、菜单模块、权限模块功能,非常实用。

学习点一:

 构建数据库表结构(通用)

     1.用户表 (可根据角色,添加相应字段)

-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user`  (
  `user_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '姓名',
  `account` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '登录账户(8位字母)',
  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码',
  `status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '状态(0-正常;1-不可用)',
  `create_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
  `create_id` bigint(11) NULL DEFAULT NULL COMMENT '创建人id',
  `update_time` timestamp(6) NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '修改时间',
  `update_id` bigint(20) NULL DEFAULT NULL COMMENT '修改人id',
  PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 41 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

    2.角色表

-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role`  (
  `role_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色名称',
  `remarks` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注',
  `status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '状态(0-正常;1-不可用)',
  `create_time` timestamp(6) NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
  `create_id` bigint(11) NULL DEFAULT NULL COMMENT '创建人id',
  `update_time` timestamp(6) NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '修改时间',
  `update_id` bigint(20) NULL DEFAULT NULL COMMENT '修改人id',
  PRIMARY KEY (`role_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 24 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

 3.角色用户表

-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) NOT NULL COMMENT '用户ID',
  `role_id` bigint(20) NOT NULL COMMENT '角色ID',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `user_id_unique`(`user_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 182 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

 4.菜单表

-- ----------------------------
-- Table structure for sys_menu
-- ----------------------------
DROP TABLE IF EXISTS `sys_menu`;
CREATE TABLE `sys_menu`  (
  `menu_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '菜单名称',
  `icon` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '菜单对应的图标',
  `parent_id` bigint(20) NULL DEFAULT NULL COMMENT '父菜单id',
  `status` tinyint(255) NOT NULL DEFAULT 0 COMMENT '0-可用;1-不可用',
  `identity` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '路由信息',
  PRIMARY KEY (`menu_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 46 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

5.权限表(shiro框架特有)

-- ----------------------------
-- Table structure for sys_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission`  (
  `permission_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '权限名称',
  `sn` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '权限对应URL编号 例(order:pay)',
  `resources` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限对应的url(shiro框架用,例 order/pay)',
  `parent_id` bigint(20) NULL DEFAULT NULL COMMENT '父id',
  `menu_id` bigint(20) NULL DEFAULT NULL COMMENT '菜单id',
  `status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '状态(0-可用;1-不可用)',
  PRIMARY KEY (`permission_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 96 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

6.角色权限表(shiro框架特有) 

-- ----------------------------
-- Table structure for sys_role_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_permission`;
CREATE TABLE `sys_role_permission`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `role_id` bigint(20) NULL DEFAULT NULL COMMENT '角色id',
  `permission_id` bigint(20) NULL DEFAULT NULL COMMENT '资源id',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1177506881387504299 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色资源信息表' ROW_FORMAT = Dynamic;

学习点二

   数据库操作,主要采用mybatis-plus

  permissionMapper.xml(注:1.需要修改文件中实体和mapper位置)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sf.vsolution.hb.sfce.mapper.PermissionMapper" >
<resultMap id="BaseResultMap" type="com.sf.vsolution.hb.sfce.pojo.entity.Permission" >
<id column="permission_id" property="permissionId" jdbcType="BIGINT" />
<result column="name" property="name" jdbcType="VARCHAR" />
<result column="sn" property="sn" jdbcType="VARCHAR" />
<result column="resources" property="resources" jdbcType="VARCHAR" />
<result column="parent_id" property="parentId" jdbcType="BIGINT" />
<result column="menu_id" property="menuId" jdbcType="BIGINT" />
<result column="status" property="status" jdbcType="TINYINT" />
</resultMap>

<!-- 根据用多个角色id查询拥有的权限-->
<select id="getPermissionsByRoles" resultMap="BaseResultMap" parameterType="java.util.List" >
SELECT DISTINCT * FROM(
SELECT p.* FROM sys_permission p
LEFT JOIN sys_role_permission rp ON p.permission_id = rp.permission_id
WHERE rp.role_id in
<foreach collection="roleIds" index="index" item="id" open="(" separator="," close=")">
#{id}
</foreach>
AND p.`status` = 0 AND p.sn IS NOT NULL
ORDER BY p.permission_id
) a
</select>

<!-- 查询系统所有有效权限-->
<select id="getAllPermissions" resultMap="BaseResultMap" >
select permission_id, `name`, sn, resources, parent_id, menu_id, `status` from sys_permission
WHERE `status` = 0 AND sn IS NOT NULL AND resources IS NOT NULL
</select>

</mapper>

  permissionMapper

package com.sf.vsolution.hb.sfce.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.sf.vsolution.hb.sfce.pojo.entity.Permission;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * @description: 权限接口
 * @author: zhucj
 * @date: 2019-11-13 9:33
 */
@Repository
public interface PermissionMapper extends BaseMapper<Permission> {



    /**
     * 根据用多个角色id查询拥有的权限
     * @param roleIds
     * @return List
     */
    List<Permission> getPermissionsByRoles(@Param("roleIds") List<Long> roleIds);


    /**
     * 查询系统所有有效权限
     * @return List
     */
    List<Permission> getAllPermissions();


}

 permissionService

package com.sf.vsolution.hb.sfce.service;


import com.baomidou.mybatisplus.extension.service.IService;
import com.sf.vsolution.hb.sfce.pojo.entity.Permission;
import com.sf.vsolution.hb.sfce.pojo.entity.Role;

import java.util.List;

/**
 * @Description shiro框架权限控制
 * @Author zhucj
 * @Date 2019/5/6 17:13
 */
public interface PermissionService {

    /**
     * 根据用户的多个角色查询拥有的权限
     * @param roles
     * @return List
     */
    List<Permission> findPermissionsByRoles(List<Role> roles);


    /**
     * 查询系统所有有效权限
     * @return List
     */
    List<Permission> loadAllPermissions();
}

 PermissionServiceImpl

package com.sf.vsolution.hb.sfce.service.impl;
import com.sf.vsolution.hb.sfce.mapper.PermissionMapper;
import com.sf.vsolution.hb.sfce.pojo.entity.Permission;
import com.sf.vsolution.hb.sfce.pojo.entity.Role;
import com.sf.vsolution.hb.sfce.service.PermissionService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName PermissionServiceImpl
 * @Description PermissionServiceImpl
 * @Author YangLei
 * @Date 2019/5/7 10:47
 * @Version 1.0
 **/
@Service
public class PermissionServiceImpl implements PermissionService {

    private static final Logger log = LoggerFactory.getLogger(PermissionServiceImpl.class);

    @Autowired
    private PermissionMapper permissionMapper;

    @Override
    public List<Permission> findPermissionsByRoles(List<Role> roles){
        List<Long> roleIds = new ArrayList<>();
        for (Role role : roles) {
            if(role != null){
                roleIds.add(role.getRoleId());
            }
        }
        if(roleIds.size() <= 0){
            return null;
        }
        try{
            return permissionMapper.getPermissionsByRoles(roleIds);
        }catch (Exception e){
            log.error("根据用户角色查询拥有权限时异常:{}" , e);
            return null;
        }
    }

    @Override
    public List<Permission> loadAllPermissions() {
        return permissionMapper.getAllPermissions();
    }
}

学习点三

  ShiroRealm 权限的校验,每次请求接口是,获取当前角色信息权限,交给shiro框架

package com.sf.detectcore.config.shiro;

import com.sf.detectcore.config.constant.SystemConstants;
import com.sf.detectcore.entity.SysPermission;
import com.sf.detectcore.entity.SysRole;
import com.sf.detectcore.service.SysPermissionService;
import org.apache.shiro.SecurityUtils;
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.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @ClassName ShiroRealm
 * @Description shiro Realm
 * @Author huyong
 * @Date 2019/10/16 17:34
 * @Version 1.0
 */
public class ShiroRealm extends AuthorizingRealm {

    private static final Logger log = LoggerFactory.getLogger(ShiroRealm.class);

    @Autowired
    SysPermissionService sysPermissionService;


    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        Subject subject = SecurityUtils.getSubject();
        List<SysRole> roles = (List)subject.getSession().getAttribute(SystemConstants.SESSION_USER_ROLES);
        // 查询用户拥有的权限并交给shiro框架
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        List<SysPermission> permissions = sysPermissionService.findPermissionsByRoles(roles);
        Set<String> sns = new HashSet<>();
        for (SysPermission permission : permissions) {
            if (null == permission || StringUtils.isEmpty(permission.getResources())) {
                continue;
            }
            sns.add(permission.getSn());
        }
        //log.info("当前用户拥有的权限包括:{}" ,sns.toString());
        info.addStringPermissions(sns);
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken upToken = (UsernamePasswordToken)token;

        String account = (String)upToken.getPrincipal();
        char[] pwd = upToken.getPassword();
        StringBuilder sb = new StringBuilder();
        for (char c : pwd) {
            sb.append(c);
        }
        // 1.认证工号
        Object principal = account;
        // 2.认证密码
        Object credentials = sb.toString();
        // 框架进行登录判断
        return new SimpleAuthenticationInfo(principal, credentials, getName());
    }
}

ShiroConfig 权限的配置,配置特别接口和加载权限内容,权限拦截接口


package com.sf.vsolution.hb.sfce.util.shiro;

import com.sf.vsolution.hb.sfce.pojo.entity.Permission;
import com.sf.vsolution.hb.sfce.service.PermissionService;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.DelegatingFilterProxy;

import java.util.*;

/**
* @ClassName ShiroConfig
* @Description 权限框架相关配置
* @Author YangLei
* @Date 2019/5/7 10:30
* @Version 1.0
**/

@Configuration
public class ShiroConfig {
private static Logger log = LoggerFactory.getLogger(ShiroConfig.class);

@Autowired
PermissionService permissionService;

/**
* 注入ShiroRealm
*/
@Bean
public ShiroRealm shiroRealm() {
return new ShiroRealm();
}

/**
* 注入securityManager
*/
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
manager.setRealm(shiroRealm());
return manager;
}

@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
//1 定义shiroFactoryBean
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
//2 设置securityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);

//设置默认登录的url
shiroFilterFactoryBean.setLoginUrl("/login/goLogin");
shiroFilterFactoryBean.setUnauthorizedUrl("/login/unauthorized");

//3 查询系统中所有权限并交给shiro框架
Map<String,String> result = new LinkedHashMap<>();
// authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问
/* ===============静态资源放行区================== */
result.put("/resources/**", "anon");
result.put("/druid/**", "anon");
result.put("/static/**", "anon");
result.put("/swagger/**", "anon");
result.put("/swagger-ui.html", "anon");
result.put("/swagger-resources/**", "anon");
result.put("/webjars/**", "anon");
result.put("/v2/api-docs", "anon");
result.put("/index.html", "anon");
result.put("/order.html", "anon");
result.put("/css/**", "anon");
result.put("/fonts/**", "anon");
result.put("/img/**", "anon");
result.put("/js/**", "anon");
result.put("/favicon.ico*", "anon");

/*===============项目测试接口放行区================*/
result.put("/test/order", "anon");

/*===============项目部分接口放行区================*/
// h5下单接口
result.put("/order/createOrder", "anon");


/*===============特定接口放行区================*/
//注销,退出登录
result.put("/login/logout", "logout");
//拦截到登录(返回json,前端控制跳转到登录页面)
result.put("/login/goLogin", "anon");
//用户名密码登录
result.put("/login/login", "anon");
result.put("/login", "anon");
result.put("/login/logout", "anon");
//登录验证码相关
result.put("/login/getVerifyCodeImage" , "anon");
result.put("/login/getVerifyCodeTest" , "anon");

/*===============登录后需要有权限才能访问区================*/
List<Permission> permissions = permissionService.loadAllPermissions();
for (Permission permission : permissions) {
if (permission.getResources()==null || permission.getSn() == null) {
continue;
}
String resource = permission.getResources();
String perm = "perms[" + permission.getSn() +"]";
result.put(resource, perm);
}
/*===============拦截上述以外,所有接口区================*/
result.put("/**", "authc");
Set<Map.Entry<String, String>> set = result.entrySet();
Iterator<Map.Entry<String, String>> it = set.iterator();
//过滤为空的
Set<String> keys = result.keySet();
Map<String,String> map = new LinkedHashMap<>();
for(String key : keys){
if(!StringUtils.isEmpty(key) && !StringUtils.isEmpty(result.get(key))){
map.put(key, result.get(key));
}
}
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
log.info("Project All permission:{}",result);
return shiroFilterFactoryBean;
}



/**
* 注册AuthorizationAttributeSourceAdvisor
* 如果要开启注解@RequiresRoles等注解,必须添加
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager manager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(manager);
return advisor;
}


@Bean
public FilterRegistrationBean delegatingFilterProxy(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
DelegatingFilterProxy proxy = new DelegatingFilterProxy();
proxy.setTargetFilterLifecycle(true);
proxy.setTargetBeanName("shiroFilter");
filterRegistrationBean.setFilter(proxy);
return filterRegistrationBean;
}
}
 

依赖maven支持

<!-- SpringBoot AOP包,用于Shiro授权 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <!--Shiro核心包 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.4.0</version>
        </dependency>
   <!--fastJson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
 <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.2</version>
            <scope>provided</scope>
        </dependency>

 

 

posted on 2019-11-20 13:27  追风筝的人123  阅读(2418)  评论(0编辑  收藏  举报

导航