2019-11-20 Java项目实战-shiro框架使用

人走茶凉 提交于 2019-12-05 02:15:13

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 **/@Configurationpublic 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;    }}
 

 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!