首页 > 其他分享 >Shiro-使用笔记

Shiro-使用笔记

时间:2023-07-28 21:25:04浏览次数:60  
标签:笔记 shiro perm role user 使用 tb id Shiro

目录

零、资料

一、使用

1.1、环境搭建

  • SpringBoot2
  • Mybatis3
  • MySQL8.0
  • Shiro

1.1.1、创建数据库

create database db_shiro_demo;
  
drop table if exists tb_user;
create table tb_user(
	id int primary key auto_increment,
	user_name varchar(50),
	pwd varchar(500)	
);
INSERT INTO `db_shiro_demo`.`tb_user` (`id`, `user_name`, `pwd`) VALUES (1, 'zs', '123');
INSERT INTO `db_shiro_demo`.`tb_user` (`id`, `user_name`, `pwd`) VALUES (2, 'ls', '123');



drop table if exists tb_role;
create table tb_role(
	id int primary key auto_increment,
	role_name varchar(50)
);
INSERT INTO `db_shiro_demo`.`tb_role` (`id`, `role_name`) VALUES (1, 'admin');
INSERT INTO `db_shiro_demo`.`tb_role` (`id`, `role_name`) VALUES (2, 'normal');




drop table if exists tb_perm;
create table tb_perm(
	id int primary key auto_increment,
	perm_name varchar(50)
);
INSERT INTO `db_shiro_demo`.`tb_perm` (`id`, `perm_name`) VALUES (1, 'add');
INSERT INTO `db_shiro_demo`.`tb_perm` (`id`, `perm_name`) VALUES (2, 'del');
INSERT INTO `db_shiro_demo`.`tb_perm` (`id`, `perm_name`) VALUES (3, 'update');
INSERT INTO `db_shiro_demo`.`tb_perm` (`id`, `perm_name`) VALUES (4, 'find');



drop table if exists tb_mid_role_perm;
create table tb_mid_role_perm(
	id int primary key auto_increment,
	role_id int,
	perm_id int
);
INSERT INTO `db_shiro_demo`.`tb_mid_role_perm` (`id`, `role_id`, `perm_id`) VALUES (1, 1, 1);
INSERT INTO `db_shiro_demo`.`tb_mid_role_perm` (`id`, `role_id`, `perm_id`) VALUES (2, 1, 2);
INSERT INTO `db_shiro_demo`.`tb_mid_role_perm` (`id`, `role_id`, `perm_id`) VALUES (3, 1, 3);
INSERT INTO `db_shiro_demo`.`tb_mid_role_perm` (`id`, `role_id`, `perm_id`) VALUES (4, 1, 4);
INSERT INTO `db_shiro_demo`.`tb_mid_role_perm` (`id`, `role_id`, `perm_id`) VALUES (5, 2, 4);



drop table if exists tb_mid_user_role;
create table tb_mid_user_role(
	id int primary key auto_increment,
	user_id int,
	role_id int
);
INSERT INTO `db_shiro_demo`.`tb_mid_user_role` (`id`, `user_id`, `role_id`) VALUES (1, 1, 1);
INSERT INTO `db_shiro_demo`.`tb_mid_user_role` (`id`, `user_id`, `role_id`) VALUES (2, 2, 2);


-- 【约定】:用户zs: 增删改查;用户ls:查


1.1.2、导入依赖

maven依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.14</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>


    <groupId>com.cyw</groupId>
    <artifactId>shiro-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>shiro-demo</name>
    <description>shiro-demo</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.3.1</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter-test</artifactId>
            <version>2.3.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.12.0</version>
        </dependency>


    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

1.1.3、编写springboot配置文件

server:
  port: 8000
mybatis:
  mapper-locations: classpath:/mapper/*Mapper.xml
  configuration:
    map-underscore-to-camel-case: true
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db_shiro_demo?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true
    username: root
    password: root

logging:
  level:
    com.cyw.shirodemo.mapper: info

1.1.4、创建 统一结果集类 + pojo + DTO

统一结果集类 Rst

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Rst<T> {
    private Integer code;
    private Boolean flag;
    private String msg;
    private T data;

    public static <T> Rst<T> ok() {
        return new Rst<>(2000, true, "请求成功", null);
    }

    public static <T> Rst<T> ok(String msg) {
        return new Rst<>(2000, true, msg, null);
    }

    public static <T> Rst<T> ok(String msg, T data) {
        return new Rst<>(2000, true, msg, data);
    }

    public static <T> Rst<T> ok(Integer code, String msg, T data) {
        return new Rst<>(code, true, msg, data);
    }

    public static <T> Rst<T> err() {
        return new Rst<>(4000, false, "请求失败", null);
    }

    public static <T> Rst<T> err(String msg) {
        return new Rst<>(4000, false, msg, null);
    }

    public static <T> Rst<T> err(Integer code, String msg) {
        return new Rst<>(code, false, msg, null);
    }
    public static <T> Rst<T> err(Integer code, String msg,T data) {
        return new Rst<>(code, false, msg, data);
    }

}

用户 User

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer id;
    private String userName;
    private String pwd;
    private List<Role> roleList;
}

角色 Role

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Role {
    private Integer id;
    private String roleName;
    private List<Perm> permList;
} 

权限 Perm

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Perm {
    private Integer id;
    private String permName;
}

UserDto

@AllArgsConstructor
@NoArgsConstructor
@Data
public class UserDto{
    private Integer id;
    private String userName;
    private String pwd;
    private Set<String> roleStrSet;
    private Set<String> permStrSet;
}

1.1.5、mapper接口及xml

UserMapper.java

@Mapper
public interface UserMapper {
    User findUserByName(String userName);
}

UserMapper.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="com.cyw.shirodemo.mapper.UserMapper">

    <resultMap id="BaseResultMap" type="com.cyw.shirodemo.pojo.User">
            <id property="id" column="id" jdbcType="INTEGER"/>
            <result property="userName" column="user_name" jdbcType="VARCHAR"/>
            <result property="pwd" column="pwd" jdbcType="VARCHAR"/>
            <collection property="roleList" ofType="com.cyw.shirodemo.pojo.Role">
                <id property="id" column="role_id"/>
                <result property="roleName" column="role_name"/>
            </collection>
    </resultMap>

    <sql id="Base_Column_List">
        tb_user.id,
        tb_user.user_name,
        tb_user.pwd
    </sql>

    <select id="findUserByName" resultMap="BaseResultMap">
        select <include refid="Base_Column_List"></include>,tb_mid_user_role.role_id,tb_role.role_name
            from tb_user,tb_role,tb_mid_user_role
            where
                tb_user.id = tb_mid_user_role.user_id
                and tb_mid_user_role.role_id = tb_role.id
                and tb_user.user_name=#{userName}
    </select>

</mapper>

PermMapper.java

@Mapper
public interface PermMapper {
    List<Perm> findPermListByRoleName(String roleName);
}

PermMapper.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="com.cyw.shirodemo.mapper.PermMapper">

    <resultMap id="BaseResultMap" type="com.cyw.shirodemo.pojo.Perm">
            <id property="id" column="id" jdbcType="INTEGER"/>
            <result property="permName" column="perm_name" jdbcType="VARCHAR"/>
    </resultMap>

    <sql id="Base_Column_List">
        tb_perm.id,tb_perm.perm_name
    </sql>

    <select id="findPermListByRoleName" resultType="com.cyw.shirodemo.pojo.Perm">
        select tb_perm.*
        from tb_role,tb_mid_role_perm,tb_perm
        where
            tb_role.id = tb_mid_role_perm.role_id
            and tb_mid_role_perm.perm_id = tb_perm.id
            and tb_role.role_name = #{roleName}
    </select> 

</mapper>

1.1.6、service接口及实现类

UserService:

public interface UserService {
    User findUserByName(String userName);
    UserDto findUserWithRoleAndPerm(String userName);
}

UserServiceImpl:


@AllArgsConstructor
@Transactional
@Service("userService")
public class UserServiceImpl implements UserService {
    private UserMapper userMapper;
    private PermMapper permMapper;

    /**
     * 按用户名查询用户信息
     * @param userName
     * @return
     */
    @Override
    public User findUserByName(String userName) {
        return userMapper.findUserByName(userName);
    }
    
    /**
     * 按用户名查询带有权限的用户信息
     * @param principal
     * @return
     */
    @Override
    public UserDto findUserWithRoleAndPerm(String principal) {

        User user = userMapper.findUserByName(principal);
        UserDto userDto = new UserDto();
        BeanUtils.copyProperties(user,userDto);

        Set<String> roleSet = new HashSet<>();
        Set<String> permSet = new HashSet<>();
        user.getRoleList()
                .forEach(role -> {
                    roleSet.add(role.getRoleName());

                    List<Perm> permListByRoleName = permMapper.findPermListByRoleName(role.getRoleName());
                    Set<String> permSetTmp = permListByRoleName.stream()
                            .map(Perm::getPermName).collect(Collectors.toSet());
                    permSet.addAll(permSetTmp);
                });
        userDto.setRoleStrSet(roleSet);
        userDto.setPermStrSet(permSet);
        return userDto;
    }

}

1.1.7、shiro操作数据库的类

MyRealm.java

@Component
@AllArgsConstructor
public class MyRealm extends AuthorizingRealm {

    private UserService userService;


    /**
     * 认证(登录)的处理
     *
     * @param token the authentication token containing the user's principal and credentials.
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        
        // 来自浏览器的用户名和密码
        String principal = (String) token.getPrincipal();
        
        // 按用户名从数据中查询用户信息
        User user = userService.findUserByName(principal);

        if (user == null) {
            throw new UnknownAccountException("用户不存在");
        }

        // 返回数据库中能正确登录的用户信息给shiro
        return new SimpleAuthenticationInfo(principal, user.getPwd(), "myRealm");
    }


    /**
     * 授权的处理
     *
     * @param principals the primary identifying principals of the AuthorizationInfo that should be retrieved.
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        
        // 浏览器传过来的用户名
        String principal = (String) principals.getPrimaryPrincipal();

        // 从数据库中根据浏览器传过来的用户名查询带有角色和权限的用户信息
        UserDto userDto = userService.findUserWithRoleAndPerm(principal);
        
        // 将带有权限的用户信息封装为shiro能够识别的用户信息对象AuthorizationInfo
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setRoles(userDto.getRoleStrSet());
        simpleAuthorizationInfo.setStringPermissions(userDto.getPermStrSet());

        return simpleAuthorizationInfo;
    }

}

1.1.8、shiro的配置类

ShiroConfig.java

@Configuration
public class ShiroConfig {

    @Bean
    public DefaultSecurityManager defaultSecurityManager(MyRealm myRealm){
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager(myRealm);
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        return defaultSecurityManager;
    }

}

1.1.9、统一异常处理

GlobalExceptionHandler.java:

@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {

    @ExceptionHandler(IncorrectCredentialsException.class)
    public Rst<Void> err() {
        return Rst.err("用户名或密码错误");
    }

    @ExceptionHandler(Exception.class)
    public Rst<Void> err(Exception exception) {
        return Rst.err(exception.getMessage());
    }
}

1.1.10、controller

UserController.java:

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;  

@AllArgsConstructor
@RestController
@RequestMapping("/user")
public class UserController {

    @PostMapping("/login")
    public Rst<String> login(User user) throws IncorrectCredentialsException{
        System.out.println("=== 正在登陆。。。");
        
        // 将用户信息转化为shiro能识别的用户信息UsernamePasswordToken 
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(), user.getPwd());  
         
        // 从shiro提供的容器工具类SecurityUtils获取 Subject 对象,通过 Subject 对象可以执行shiro封装过的登录方法
        Subject subject = SecurityUtils.getSubject();
        subject.login(token);

        return Rst.ok("登录成功",token.getUsername());
    }

    @GetMapping("/logout")
    public Rst<Void> logout() {
        System.out.println("=== 正在注销。。。");

        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return Rst.ok("注销成功");
    }

}

1.1.11、前端

登录页:

主页:

标签:笔记,shiro,perm,role,user,使用,tb,id,Shiro
From: https://www.cnblogs.com/cywdder/p/17588844.html

相关文章

  • 【算法】哈希学习笔记
    1.哈希(hash)简介1.1前言又来写算法总结了qwq。今天是2023/7/8,期末考试已经考完了。初二下注定是一个煎熬的学期,所以我在这一学期并没有学什么新算法,OI也没什么长进。但倒是深造了几个算法,比如:dp,hash,线段树。之前一直想写一篇hash的学习笔记,但由于种种原因,并没有写成。于......
  • 基于VScode的wsl2的conda使用
    一、安装conda环境(基于docker的)1.1MicroSoft对于wsl2和docker的官方解释:https://learn.microsoft.com/en-us/windows/wsl/use-custom-distro1.2对于docker和wsl2原理解析:https://zhuanlan.zhihu.com/p/4817409141.3安装完docker环境和container环境后直接在VScode中......
  • 使用scp在Linux服务器之间传输文件
    第一章、scp命令介绍scp就是securecopy,一个在linux下用来进行远程拷贝文件的命令。scp文件名1远程用户名@IP地址:文件名2几个参数:-v用来显示进度.可以用来查看连接-C使能压缩选项-P选择端口-4强行使用IPV4地址.-6强行使用IPV6地址.第二章、实......
  • Oracle使用spool导出数据
    第一章、导出参数设置settermoff--关闭,不在屏幕上展示结果settrimspoolon--打开,去除重定向(spool)输出美航的拖尾控股,缺省为offsetechooff--关闭,避免打印sql,西安市start启动的脚本中每个sql指令,缺省为onsetfeedbackoff--关闭,避免展示,回现本次sql处理的记录条......
  • odoo Widget使用大全
    odoo中有众多原生的widget,覆盖了很多使用场景,可惜的是odoo官方并未整理出一份使用文档.本章将根据实际使用情况来对常见的诸多widget的使用方法集中介绍一下.已知的可用Widget列表float_timemany2manyattendeemany2many_tagsone2manyemailmail_followersmail_threadm......
  • EPLAN电气绘图笔记
    EPLAN的背景由来发展意义使用软件的一些思维上规则的东西。引入一些新的概念性名词术语及区分介绍。如何完成项目式交付初级标准电气图纸。如何高效简化。   未完待续。。。 ......
  • JProfiler的安装与使用
    JProfiler的安装与使用JProfiler是由ej-technologiesGmbH公司开发的一个用于分析JVM内部情况的专业工具。在研发过程中可以使用JProfiler,用于质量保证,也可以用于解决生产系统遇到的问题。JProfiler处理的主要问题Methodcalls(方法调用)通常被称为"CPU分析"。方法调用可以......
  • 春秋战国笔记
    鲁  臧文仲 臧宣叔 臧石齐 高无  颜庚 -颜晋2  相.田常 田盘 田布 公孙会 田和  齐康公 田无宇..田乞2栾氏 高氏 鲍氏灵公..庄公   崔杼景公  庆封  晏子 悼公 国夏 高张 田乞.相简公 平公 田悼子5 田白4 田常.3田盘2田乞1 康公 田和.齐太公.......
  • 使用阿里云搭建网站并实现站库分离
    使用阿里云搭建自己的网站并用阿里云RDS实现站库分离,本文章将从注册域名到部署网站详细地讲解。什么是站库分离:站库分离就是网站和数据库不在同一个服务器上,数据库用的是内网网络;这样的操作模式更快,更安全;很多大型的企业都采用站库分离的模式。推荐几个网站程序,自己根据需要选择:论......
  • STM32使用硬件IIC读取SHTC3温湿度传感器 显示在OLED屏上
    STM32使用硬件I2C读取SHTC3温湿度传感器的数据并显示在0.96寸OLED屏上。我用的是STM32F103C8T6,程序用的是ST标准库写的。实现效果图I2C协议简介I2C通讯协议(Inter-IntegratedCircuit)是由Phiilps公司开发的,由于它引脚少,硬件实现简单,可扩展性强,不需要USART、CAN等通讯协议的外......