Shiro是Apache 的一个强大且易用的Java安全框架,执行身份验证、授权、密码学和会话管理。Shiro 主要分为两个部分就是认证和授权两部分

一、介绍

  1. Subject代表了当前用户的安全操作

  2. SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。

  3. Authenticator即认证器,对用户身份进行认证,Authenticator是一个接口,shiro提供ModularRealmAuthenticator实现类,通过ModularRealmAuthenticator基本上可以满足大多数需求,也可以自定义认证器。

  4. Authorizer即授权器,用户通过认证器认证通过,在访问功能时需要通过授权器判断用户是否有此功能的操作权限。

  5. Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。

  6. sessionManager即会话管理,shiro框架定义了一套会话管理,它不依赖web容器的session,所以shiro可以使用在非web应用上。

Shiro相关类介绍

  • (1)Authentication 认证 —— 用户登录

  • (2)Authorization 授权 —- 用户具有哪些权限

  • (3)Cryptography 安全数据加密

  • (4)Session Management 会话管理

  • (5)Web Integration web系统集成

  • (6)Interations 集成其它应用,spring、缓存框架

二、依赖引入

完整的pom文件如下:

<?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 http://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.4.1</version>
<relativePath></relativePath> <!-- lookup parent from repository -->
</parent>
<groupId>com.gt.shiro</groupId>
<artifactId>com.sunyue.shiro</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<java.version>1.8</java.version>
<druid.verzion>1.1.10</druid.verzion>
<pagehelper.version>1.2.10</pagehelper.version>
<mybatis.version>2.1.4</mybatis.version>
<thymeleaf-layout-dialect.version>2.0.4</thymeleaf-layout-dialect.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- 排除默认的tomcat -->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 重新依赖Jetty的starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<!--shiro整合spring-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.verzion}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pagehelper.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</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>
</dependencies>
<build>
<plugins>
<!-- spring boot maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.gt.shiro.SpringShiroApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>

三、配置文件

application.yml配置文件:
# 开发时关闭缓存,不然没法看到实时页面
spring.thymeleaf.cache=false
# 用非严格的 HTML
spring.thymeleaf.mode=HTML
spring.thymeleaf.encoding=utf-8
spring.thymeleaf.servlet.content-type=text/html
spring.datasource.druid.url=jdbc:mysql://localhost:3306/shiro?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
spring.datasource.druid.username=root
spring.datasource.druid.password=admin
spring.datasource.druid.initial-size=1
spring.datasource.druid.min-idle=1
spring.datasource.druid.max-active=20
spring.datasource.druid.test-on-borrow=true
#springbootjdbc导入包不和以前一样
spring.datasource.druid.driver-class-name= com.mysql.cj.jdbc.Driver
mybatis.type-aliases-package=com.gt.shiro.entity
mybatis.mapper-locations=classpath:mapper/*.xml
#打印数据库的操作
logging.level.com.example.springsecurity.dao=debug
#redis缓存
### 配置Redis
mybatis.configuration.cache-enabled=true
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=...
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=sunyue
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-idle=200
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=1000

Shiro两个重要的配置类:

  • 1.UserRealm

      package com.gt.shiro.config;
    import com.gt.shiro.entity.TestUser;
    import com.gt.shiro.server.TestUserServer;
    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.springframework.beans.factory.annotation.Autowired;
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    public class UserRealm extends AuthorizingRealm {
    @Autowired
    private TestUserServer testUserServer;
    /**
    * 执行授权逻辑
    *
    * @param principalCollection
    * @return
    */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    System.out.println("执行授权逻辑");
    /*获取当前登录的用户信息*/
    Subject subject = SecurityUtils.getSubject();
    TestUser testUser = (TestUser) subject.getPrincipal();
    //设置角色,多个角色
    /*Set<String> rolesSet = new HashSet<>();
    rolesSet.add(testUser.getRole());*/
    //SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(rolesSet);
    //给资源进行授权
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    /*可以在以下list加入多个权限*/
    /*List<String> roles = new ArrayList<>();
    roles.add(testUser.getPerms());
    info.addRoles(roles);*/
    //设置权限
    info.addRole(testUser.getRole());
    //需要判断权限是否为空值(null是没有地址,""是有地址但是里面的内容是空的)
    if (testUser.getPerms() != null && !testUser.getPerms().equals("")) {
    info.addStringPermission(testUser.getPerms());
    }
    return info;
    }
    /**
    * 执行认证逻辑
    *
    * @param authenticationToken
    * @return
    * @throws AuthenticationException
    */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    System.out.println("执行认证逻辑");
    /*获取令牌*/
    UsernamePasswordToken passwordToken = (UsernamePasswordToken) authenticationToken;
    //取出用户名并且判断用户名是否和数据库一致
    TestUser testUser = testUserServer.selectOneByName(passwordToken.getUsername());
    if (testUser != null) {
    //进行认证,将正确数据给shiro处理
    //密码不用自己比对,AuthenticationInfo认证信息对象,一个接口,new他的实现类对象SimpleAuthenticationInfo
    /* 第一个参数随便放,可以放user对象,程序可在任意位置获取 放入的对象
    * 第二个参数必须放密码,
    * 第三个参数放 当前realm的名字,因为可能有多个realm*/
    //若密码不正确则返回IncorrectCredentialsException异常
    return new SimpleAuthenticationInfo(testUser, testUser.getPassword(), this.getName());
    }
    //若用户名不存在则返回UnknownAccountException异常
    return null;
    }
    }
  • 2.ShiroConfig

      package com.gt.shiro.config;
    import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
    import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
    import java.util.LinkedHashMap;
    import java.util.Map;
    import java.util.Properties;
    @Configuration
    public class ShiroConfig {
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    //设置安全管理器
    shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
    //添加一些Shiro的内置过滤器
    /**
    * Shiro 的内置过滤器可以实现权限的相关拦截
    * 常用过滤器
    * 1.anon:无需认证
    * 2.authc:必须认证才能访问
    * 3.user:如果使用rememberme功能可以访问
    * 4.perms:对应权限才能访问
    * 5.role:对应角色才能访问
    */
    //登录状态下才可以访问main页面,manage权限可访问manage页面,admin角色可访问admin页面
    Map<String, String> filterMap = new LinkedHashMap<String, String>();
    filterMap.put("/main", "authc");
    filterMap.put("/manage", "perms[manage]");
    filterMap.put("/admin", "roles[admin]");
    shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
    //未登录状态下访问将跳转至login页面
    // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
    shiroFilterFactoryBean.setLoginUrl("/login");
    // 登录成功后要跳转的链接
    shiroFilterFactoryBean.setSuccessUrl("/");
    //无授限状态下访问将请求unauthor
    shiroFilterFactoryBean.setUnauthorizedUrl("/unAuth");
    return shiroFilterFactoryBean;
    }
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
    DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
    //DefaultWebSecurityManager需要关联一个Realm
    defaultWebSecurityManager.setRealm(userRealm);
    return defaultWebSecurityManager;
    }
    /**
    * 创建realm
    */
    @Bean(name = "userRealm")
    public UserRealm getRealm() {
    return new UserRealm();
    }
    @Bean
    public ShiroDialect shiroDialect() {
    return new ShiroDialect();
    }
    /**
    * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions)
    * 配置以下两个bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)即可实现此功能
    *
    * @return
    */
    @Bean
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
    DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
    advisorAutoProxyCreator.setProxyTargetClass(true);
    return advisorAutoProxyCreator;
    }
    /**
    * 开启 shiro 的@RequiresPermissions注解
    *
    * @param securityManager
    * @return
    */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
    AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
    authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
    return authorizationAttributeSourceAdvisor;
    }
    /**
    * shiro出现权限异常可通过此异常实现制定页面的跳转(或接口跳转)
    *
    * @return
    */
    @Bean
    public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
    SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
    Properties properties = new Properties();
    /*未授权处理页*/
    properties.setProperty("org.apache.shiro.authz.UnauthorizedException", "/error.html");
    /*身份没有验证*/
    properties.setProperty("org.apache.shiro.authz.UnauthenticatedException", "/error.html");
    resolver.setExceptionMappings(properties);
    return resolver;
    }
    }

四、数据连接和业务逻辑

  • 1.实体类

      package com.gt.shiro.entity;
    import lombok.Data;
    import lombok.experimental.Accessors;
    import java.io.Serializable;
    import java.util.Date;
    @Data
    @Accessors(chain = true)
    public class TestUser implements Serializable {
    private Integer id;
    private String username;
    private String password;
    /*权限*/
    private String perms;
    /*角色*/
    private String role;
    /*加盐密码*/
    private String salt;
    }
  • 2.Dao和Mapper

      package com.gt.shiro.dao;
    import com.gt.shiro.entity.TestUser;
    import org.apache.ibatis.annotations.Mapper;
    import java.util.List;
    @Mapper
    public interface TestUserMapper {
    List<TestUser> findAll();
    TestUser selectOne(Integer id);
    TestUser selectOneByName(String username);
    void insert(TestUser testUser);
    void update(TestUser testUser);
    void delete(Integer id);
    }

<?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.gt.shiro.dao.TestUserMapper">
<select id="findAll" resultType="TestUser">
select * from test_user
</select>
<select id="selectOne" resultType="TestUser">
select * from test_user where id=#{id}
</select>
<select id="selectOneByName" resultType="TestUser">
select * from test_user where username=#{username}
</select>
<insert id="insert">
insert into test_user (id,username,password,perms,role,salt) value (#{id},#{username},#{password},#{perms},#{role},#{salt})
</insert>
<update id="update">
update test_user set username = #{username},password=#{password},perms=#{perms},role=#{role},salt=#{salt} where id = #{id}
</update>
<delete id="delete">
delete from test_user where id = #{id}
</delete>
</mapper>
  • 3.业务层及其实现

      package com.gt.shiro.server;
    import com.gt.shiro.entity.TestUser;
    import org.springframework.stereotype.Service;
    import java.util.List;
    @Service
    public interface TestUserServer {
    /*查询所有*/
    List<TestUser> selectAll();
    /*查询一个用户*/
    TestUser selectByOne(Integer id);
    /*通过名字查询一个用户*/
    TestUser selectOneByName(String name);
    /*增加一个用户*/
    void insert(TestUser testUser);
    /*删除一个用户*/
    void delete(Integer id);
    /*更新一个用户*/
    void update(TestUser testUser);
    }

package com.gt.shiro.server.serverImpl;
import com.gt.shiro.dao.TestUserMapper;
import com.gt.shiro.entity.TestUser;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.sunyue.shiro.server.TestUserServer;
import java.util.List;
@Service
public class TestUserServerImpl implements TestUserServer {
@Autowired
private TestUserMapper testUserMapper;
@Override
public List<TestUser> selectAll() {
return testUserMapper.findAll();
}
@Override
public TestUser selectByOne(Integer id) {
return testUserMapper.selectOne(id);
}
@Override
public TestUser selectOneByName(String name) {
return testUserMapper.selectOneByName(name);
}
@Override
public void insert(TestUser testUser) {
//加密写法
String salt = new SecureRandomNumberGenerator().nextBytes().toString();
String password= new SimpleHash("md5",testUser.getPassword(),salt,2).toString();
testUser.setPassword(password);
testUser.setSalt(salt);
testUserMapper.insert(testUser);
}
@Override
public void delete(Integer id) {
testUserMapper.delete(id);
}
@Override
public void update(TestUser testUser) {
testUserMapper.update(testUser);
}
}
  • 4.控制层

      package com.gt.shiro.controller;
    import com.gt.shiro.entity.TestUser;
    import com.gt.shiro.server.TestUserServer;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.IncorrectCredentialsException;
    import org.apache.shiro.authc.UnknownAccountException;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.crypto.hash.SimpleHash;
    import org.apache.shiro.subject.Subject;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.*;
    @Controller
    public class indexController {
    @Autowired
    private TestUserServer testUserServer;
    @GetMapping("/{url}")
    public String redirect(@PathVariable("url") String url) {
    return url;
    }
    @RequestMapping(value = {"/", "/index"}, method = RequestMethod.GET)
    private String index() {
    return "index";
    }
    @PostMapping("/login")
    public String login(String username, String password, Model model) {
    Subject subject = SecurityUtils.getSubject();
    TestUser testUser = testUserServer.selectOneByName(username);
    if (testUser != null) {
    //根据salt值和用户输入的密码计算加密后的密码
    String salt = testUser.getSalt();
    password = new SimpleHash("md5", password, salt, 2).toString();
    System.out.println(password);
    }
    UsernamePasswordToken token = new UsernamePasswordToken(username, password);
    //UsernamePasswordToken token = new UsernamePasswordToken(username, testUser.getPassword());(不加密写法)
    try {
    //将用户名和密码通过token传给shiro进行认证
    subject.login(token);
    TestUser user = (TestUser) subject.getPrincipal();
    subject.getSession().setAttribute("testUser", user);
    return "index";
    } catch (UnknownAccountException e) {
    e.printStackTrace();
    model.addAttribute("msg", "用户名不存在");
    return "login";
    } catch (IncorrectCredentialsException e) {
    e.printStackTrace();
    model.addAttribute("msg", "密码有误");
    return "login";
    }
    }
    @ResponseBody
    @GetMapping("/unauthor")
    public String unauthor() {
    return "权限不足,无法访问";
    }
    @GetMapping("/logout")
    public String logout() {
    Subject subject = SecurityUtils.getSubject();
    subject.logout();
    return "login";
    }
    @PostMapping("/register")
    public String register(TestUser testUser, Model model) {
    String username = testUser.getUsername();
    String password = testUser.getPassword();
    if (username ** null || username.equals("")) {
    model.addAttribute("msg", "用户名不能为空");
    return "register";
    } else if (password ** null || password.equals("")) {
    model.addAttribute("msg", "密码不能为空");
    return "register";
    } else if (testUserServer.selectOneByName(username) != null) {
    model.addAttribute("msg", "用户名已被占用");
    return "register";
    } else {
    testUserServer.insert(testUser);
    return "login";
    }
    }
    }
  • 5.前端页面

    • (1)index.html

        <!DOCTYPE html>
      <html xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.thymrleaf.org/thymeleaf-extras-shiro">
      <head>
      <meta charset="UTF-8">
      <title>Insert title here</title>
      <link rel="shortcut icon" href="#"/>
      </head>
      <body>
      <div th:if="${session.testUser != null}">
      <span th:text="'欢迎回来 '+${session.testUser.username}+'! '">
      </span><a href="/logout">退出</a>
      </div>
      <a href="/main">main</a>
      <span shiro:hasPermission="manage"> | <a href="/manage">manage</a></span>
      <span shiro:hasRole="admin"> | <a href="/admin">admin</a></span>
      <br>
      </body>
      </html>
    • (2)login.html

        <!DOCTYPE html>
      <html xmlns:th="http://www.thymeleaf.org">
      <head>
      <meta charset="UTF-8">
      <title>Insert title here</title>
      <link rel="shortcut icon" href="#"/>
      </head>
      <body>
      <form action="/login" method="post">
      <span th:text="${msg}" style="color: red"></span>
      <table>
      <tr>
      <td>用户名:</td>
      <td><input type="text" name="username"/></td>
      </tr>
      <tr>
      <td>密码:</td>
      <td><input type="password" name="password"/></td>
      </tr>
      <tr>
      <td><input type="submit" value="登录"/></td>
      <td><a href="/register">
      <button type="button" value="注册">注册</button>
      </a>
      </td>
      </tr>
      </table>
      </form>
      </body>
      </html>
    • (3)register.html

        <!DOCTYPE html>
      <html xmlns:th="http://www.thymeleaf.org">
      <head>
      <meta charset="UTF-8">
      <title>Insert title here</title>
      <link rel="shortcut icon" href="#"/>
      </head>
      <body>
      <form action="/register" method="post">
      <span th:text="${msg}" style="color: red"></span>
      <table>
      <tr>
      <td>用户名:</td>
      <td><input type="text" name="username"/></td>
      </tr>
      <tr>
      <td>密码:</td>
      <td><input type="password" name="password"/></td>
      </tr>
      <tr>
      <td><input type="submit" value="注册"/></td>
      </tr>
      </table>
      </form>
      </body>
      </html>
    • (4)main.html

        <!DOCTYPE html>
      <html>
      <head>
      <meta charset="UTF-8">
      <title>Insert title here</title>
      <link rel="shortcut icon" href="#"/>
      </head>
      <body>
      <h1>main</h1>
      </body>
      </html>
    • (5)manage.html

        <!DOCTYPE html>
      <html>
      <head>
      <meta charset="UTF-8">
      <title>Insert title here</title>
      <link rel="shortcut icon" href="#"/>
      </head>
      <body>
      <h1>manage</h1>
      </body>
      </html>
    • (6)admin.html

        <!DOCTYPE html>
      <html>
      <head>
      <meta charset="UTF-8">
      <title>Insert title here</title>
      <link rel="shortcut icon" href="#"/>
      </head>
      <body>
      <h1>admin</h1>
      </body>
      </html>
  • 6.数据库文件

      /*
    Navicat MySQL Data Transfer
    Source Server : sunyue
    Source Server Version : 50724
    Source Host : localhost:3306
    Source Database : shiro
    Target Server Type : MYSQL
    Target Server Version : 50724
    File Encoding : 65001
    Date: 2021-01-11 22:00:47
    */
    SET FOREIGN_KEY_CHECKS=0;
    -- ----------------------------
    -- Table structure for test_user
    -- ----------------------------
    DROP TABLE IF EXISTS `test_user`;
    CREATE TABLE `test_user` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `username` varchar(120) DEFAULT NULL,
    `password` varchar(120) DEFAULT NULL,
    `perms` varchar(120) DEFAULT NULL,
    `role` varchar(120) DEFAULT NULL,
    `salt` varchar(100) DEFAULT NULL,
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4;
    -- ----------------------------
    -- Records of test_user
    -- ----------------------------
    INSERT INTO `test_user` VALUES ('4', 'admin', '4867df2e009d0096c4cd8d9be8cc104c', 'manage', 'admin', 'GQR2m1N1o3nSLjtOzMITRQ**');
    INSERT INTO `test_user` VALUES ('5', 'user', '636502f40cf197dd2f4b19f56f475b24', '', '', 'Kxw3HZiFmgnlUu8fmjMY7Q**');
    INSERT INTO `test_user` VALUES ('6', 'user1', '43f3133aa7e0ef9cf8373521dff8d8e8', 'manage', null, 'J8fn4HpauvNOrlUaRl/Spg**');
    INSERT INTO `test_user` VALUES ('7', '1', '1', 'manage', null, null);

Springboot+Shiro+Mybatis+mysql实现权限安全认证的更多相关文章

  1. Springboot+Shiro+Mybatis+mysql

    一 .shiro框架 Shiro是Apache 的一个强大且易用的Java安全框架,执行身份验证.授权.密码学和会话管理.Shiro 主要分为两个部分就是认证和授权两部分 1.Subject代表了当前 ...

  2. Springboot集成mybatis(mysql),mail,mongodb,cassandra,scheduler,redis,kafka,shiro,websocket

    https://blog.csdn.net/a123demi/article/details/78234023  : Springboot集成mybatis(mysql),mail,mongodb,c ...

  3. SpringBoot+Shiro+mybatis整合实战

    SpringBoot+Shiro+mybatis整合 1. 使用Springboot版本2.0.4 与shiro的版本 引入springboot和shiro依赖 <?xml version=&q ...

  4. SpringBoot 整合 Mybatis + Mysql——XML配置方式

    一.介绍 SpringBoot有两种方法与数据库建立连接,一种是集成Mybatis,另一种用JdbcTemplate,本文主要讨论集成Mybatis方式. SpringBoot整合Mybatis也有两 ...

  5. shiro学习(五、springboot+shiro+mybatis+thymeleaf)

    入门shiro(感觉成功了)首先感谢狂神,然后我就一本正经的复制代码了 项目结构 运行效果 数据库 <dependencies> <!-- thymeleaf-shiro整合包 -- ...

  6. SpringBoot 使用Mybatis+MySql

    pom配置 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http: ...

  7. springboot+eureka+mybatis+mysql环境下报504 Gateway Time-out

    1.test环境下的数据库配置的 driver和url有问题, 在工程日志中的表现是不能打印出最新的日志,在部署前的日志能看到报错:

  8. SpringBoot&Shiro实现用户认证

    SpringBoot&Shiro实现用户认证 实现思路 思路:实现认证功能主要可以归纳为3点 1.定义一个ShiroConfig配置类,配置 SecurityManager Bean , Se ...

  9. SpringBoot整合mybatis、shiro、redis实现基于数据库的细粒度动态权限管理系统实例

    1.前言 本文主要介绍使用SpringBoot与shiro实现基于数据库的细粒度动态权限管理系统实例. 使用技术:SpringBoot.mybatis.shiro.thymeleaf.pagehelp ...

  10. Spring Cloud之路:(七)SpringBoot+Shiro实现登录认证和权限管理

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/sage_wang/article/details/79592269一.Shiro介绍1.Shiro是 ...

随机推荐

  1. golang之UrlEncode编码/UrlDecode解码

    为什么需要编码和解码 1.是因为当字符串数据以url的形式传递给web服务器时,字符串中是不允许出现空格和特殊字符的: 2.因为 url 对字符有限制,比如把一个邮箱放入 url,就需要使用 urle ...

  2. 复杂模式的两个List与Map合并为一个Map的拼接;笛卡尔乘积处理数据问题

    简介 (Introduction): 背景 数据从多个表中获取,每个表的数据条数不是唯一的,最后结果要拼接成一个Map<String,Object>的模式封装所有数据,每个数据是一条. 结 ...

  3. 模仿jinja2的模板语言实验,可用于简易框架中

    mcw_str=''' wo shi {{ name }} ''' import re class myclass(): def inithtml(self): ret1 = re.search('{ ...

  4. 微信开发者工具拉取gitlab远程代码报Pull failed原因分析:

    可能出现的原因: 本地主机上没有安装node node下载地址: 1 https://nodejs.org/zh-cn/download/ 没有保存gitlab的用户名和密码

  5. StackExchange.Redis跑起来,为什么这么溜?

    StackExchange.Redis 是一个高性能的 Redis 客户端库,主要用于 .NET 环境下与 Redis 服务器进行通信,大名鼎鼎的stackoverflow 网站就使用它.它使用异步编 ...

  6. Json.NET Converting between JSON and XML

    Json.NET supports converting JSON to XML and vice versa using the XmlNodeConverter. Elements, attrib ...

  7. C# Afroge摄像头翻转90

    1.dll和命名空间就不在此列举了,如下只是将转换方法介绍: 第一个函数: public void Rotate90() { // 计算角度,类变量 //dAngle = dAngle + 90; / ...

  8. zabbix笔记_003 配置微信告警

    配置邮件告警 安装python-requests,使用微信发送告警 发送告警报错: yum install -y python-requests 测试告警: cat weixin.py #------ ...

  9. VmWare虚拟机和主机配置为同一网段IP

    参考博客:将虚拟机IP与主机IP设置在同一网段的方法 - 天懿 - 博客园 (cnblogs.com) 主机地址 主机通过WiFi连接,地址信息为: 虚拟机配置 选择编辑-->虚拟网络编辑器-- ...

  10. Qt下载、安装及环境搭建

    1  下载 刚开始去的官网下载,需要注册账号,而且还比较麻烦,后来找到了一个安装包的链接,直接下载就好了:http://mirrors.ustc.edu.cn/qtproject/archive/qt ...