引入Shiro依赖

        <!--shiro权限框架-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>

创建pojo实体类

Account.java(账号)

package cn.com.sway.doctor.service.common.model;

import lombok.Data;

@Data
public class Account {

    private String id;
    private String mobile;
    private String password;
    private String name;

}

Role.java(角色)

package cn.com.sway.doctor.service.common.model;

public class Role {

    private String id;
    private String name;

}

Permission.java(权限)

package cn.com.sway.doctor.service.common.model;

public class Permission {

    private String id;
    private String name;

}

创建Mapper

AuthMapper.java

package cn.com.sway.doctor.service.user.mapper;

import cn.com.sway.doctor.service.common.model.Account;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;
import java.util.Map;

@Mapper
public interface AuthMapper {

    Account getAccountByMobile(String mobile);

    List<Map<String,Object>> getAccountPower(String mobile);

}

AuthMapper.xml

<?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="cn.com.sway.doctor.service.user.mapper.AuthMapper">

    <!--通过手机号查找用户信息-->
    <select id="getAccountByMobile" resultType="cn.com.sway.doctor.service.common.model.Account" parameterType="String">
        SELECT *
        FROM account
        WHERE mobile=#{mobile}
    </select>

    <!--通过手机号查找用户权限信息-->
    <select id="getAccountPower" resultType="java.util.HashMap" parameterType="String">
        SELECT account.id, account.mobile, role.name AS role, permission.id AS permission
        FROM account,
             role,
             permission,
             account_role,
             role_permission
        WHERE account.mobile=#{mobile}
          AND account.id=account_role.accountId
          AND account_role.roleId=role.id
          AND role_permission.roleId=role.id
          AND role_permission.permissionId=permission.id
    </select>

</mapper>

创建Service

AuthService.java

package cn.com.sway.doctor.service.user.service;

import cn.com.sway.doctor.service.common.model.Account;

import java.util.List;
import java.util.Map;

public interface AuthService {

    Account getAccountByMobile(String mobile);

    List<Map<String,Object>> getAccountPower(String mobile);

}

AuthServiceImpl.java

package cn.com.sway.doctor.service.user.service.impl;

import cn.com.sway.doctor.service.common.model.Account;
import cn.com.sway.doctor.service.user.mapper.AuthMapper;
import cn.com.sway.doctor.service.user.service.AuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

@Service
public class AuthServiceImpl implements AuthService {

    @Autowired
    AuthMapper authMapper;

    @Override
    public Account getAccountByMobile(String mobile) {
        return authMapper.getAccountByMobile(mobile);
    }

    @Override
    public List<Map<String, Object>> getAccountPower(String mobile) {
        return authMapper.getAccountPower(mobile);
    }
}

创建验证方法

ShiroRealm.java

package cn.com.sway.doctor.service.user.shiro;

import cn.com.sway.doctor.service.common.model.Account;
import cn.com.sway.doctor.service.user.service.AuthService;
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.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;
import java.util.Map;

public class ShiroRealm extends AuthorizingRealm {

    @Autowired
    private AuthService loginService;

    /**
     * 获取权限
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        //获取登录用户名
        String mobile = (String) principalCollection.getPrimaryPrincipal();
        //添加角色和权限
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();

        List<Map<String, Object>> powerList = loginService.getAccountPower(mobile);
        System.out.println(powerList.toString());
        for (Map<String, Object> powerMap : powerList) {
            //添加角色
            simpleAuthorizationInfo.addRole(String.valueOf(powerMap.get("role")));
            //添加权限
            simpleAuthorizationInfo.addStringPermission(String.valueOf(powerMap.get("permission")));
        }
        return simpleAuthorizationInfo;
    }

    /**
     * 登录认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //加这一步的目的是在Post请求的时候会先进认证,然后在到请求
        if (authenticationToken.getPrincipal() == null) {
            return null;
        }
        //获取用户唯一标识
        String mobile = authenticationToken.getPrincipal().toString();
        //根据用户名去数据库查询用户信息
        Account account = loginService.getAccountByMobile(mobile);
        if (account == null) {
            //这里返回后会报出对应异常
            return null;
        } else {
            //这里验证authenticationToken和simpleAuthenticationInfo的信息
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(account, account.getPassword(), getName());
            return simpleAuthenticationInfo;
        }
    }

}

创建配置文件

ShiroConfig.java

package cn.com.sway.doctor.service.user.config;

import cn.com.sway.doctor.service.user.shiro.ShiroRealm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ShiroConfig {
    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }

    //将自己的验证方式加入容器
    @Bean
    public ShiroRealm shiroRealm() {
        ShiroRealm shiroRealm = new ShiroRealm();
        return shiroRealm;
    }

    //权限管理,配置主要是Realm的管理认证
    @Bean
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(shiroRealm());
        return securityManager;
    }

    //shiro核心过滤器
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shirFilter(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);
        return shiroFilter;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}

创建数据

account表:

/*
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 50623
 Source Host           : localhost:3306
 Source Schema         : sway-doctor-service-user

 Target Server Type    : MySQL
 Target Server Version : 50623
 File Encoding         : 65001

 Date: 24/04/2023 22:12:38
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for account
-- ----------------------------
DROP TABLE IF EXISTS `account`;
CREATE TABLE `account`  (
  `id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `mobile` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

SET FOREIGN_KEY_CHECKS = 1;

role表:

/*
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 50623
 Source Host           : localhost:3306
 Source Schema         : sway-doctor-service-user

 Target Server Type    : MySQL
 Target Server Version : 50623
 File Encoding         : 65001

 Date: 24/04/2023 22:14:30
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for role
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role`  (
  `id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

SET FOREIGN_KEY_CHECKS = 1;

permission表:

/*
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 50623
 Source Host           : localhost:3306
 Source Schema         : sway-doctor-service-user

 Target Server Type    : MySQL
 Target Server Version : 50623
 File Encoding         : 65001

 Date: 24/04/2023 22:14:19
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for permission
-- ----------------------------
DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission`  (
  `id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

SET FOREIGN_KEY_CHECKS = 1;

account_role表:

/*
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 50623
 Source Host           : localhost:3306
 Source Schema         : sway-doctor-service-user

 Target Server Type    : MySQL
 Target Server Version : 50623
 File Encoding         : 65001

 Date: 24/04/2023 22:14:08
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for account_role
-- ----------------------------
DROP TABLE IF EXISTS `account_role`;
CREATE TABLE `account_role`  (
  `id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `accountId` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `roleId` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

SET FOREIGN_KEY_CHECKS = 1;

role_permission表:

/*
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 50623
 Source Host           : localhost:3306
 Source Schema         : sway-doctor-service-user

 Target Server Type    : MySQL
 Target Server Version : 50623
 File Encoding         : 65001

 Date: 24/04/2023 22:14:36
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for role_permission
-- ----------------------------
DROP TABLE IF EXISTS `role_permission`;
CREATE TABLE `role_permission`  (
  `id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `roleId` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `permissionId` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

SET FOREIGN_KEY_CHECKS = 1;

使用方法

package cn.com.sway.doctor.service.user.controller.api.v1;

import cn.com.sway.doctor.service.common.model.Account;
import cn.com.sway.doctor.service.common.query.AccountQuery;
import cn.com.sway.doctor.service.user.dao.AccountDao;
import org.apache.shiro.authz.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/v1/accounts")
public class AccountsApiControllerV1 {

    @Autowired
    private AccountDao accountDao;

    //@RequiresAuthentication
    //@RequiresGuest
    //@RequiresUser
    @RequiresRoles("admin")
    //@RequiresPermissions("account-manage")
    @ResponseBody
    @GetMapping("")
    public String query() {

        AccountQuery accountQuery = new AccountQuery();
        List<Account> list = accountDao.query(accountQuery);

        System.out.println(accountDao.query(accountQuery).size());

        return "account total: "+list.size();
    }

}