写点什么

Springboot+Shiro+Mybatis+mysql 实现权限安全认证

  • 2024-09-20
    福建
  • 本文字数:11928 字

    阅读完需:约 39 分钟

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# 用非严格的 HTMLspring.thymeleaf.mode=HTMLspring.thymeleaf.encoding=utf-8spring.thymeleaf.servlet.content-type=text/htmlspring.datasource.druid.url=jdbc:mysql://localhost:3306/shiro?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTCspring.datasource.druid.username=rootspring.datasource.druid.password=adminspring.datasource.druid.initial-size=1spring.datasource.druid.min-idle=1spring.datasource.druid.max-active=20spring.datasource.druid.test-on-borrow=true#springbootjdbc导入包不和以前一样spring.datasource.druid.driver-class-name= com.mysql.cj.jdbc.Drivermybatis.type-aliases-package=com.gt.shiro.entitymybatis.mapper-locations=classpath:mapper/*.xml#打印数据库的操作logging.level.com.example.springsecurity.dao=debug#redis缓存### 配置Redismybatis.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;@Servicepublic 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);
复制代码


文章转载自:二价亚铁

原文链接:https://www.cnblogs.com/xw-01/p/18276783

体验地址:http://www.jnpfsoft.com/?from=infoq

用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
Springboot+Shiro+Mybatis+mysql实现权限安全认证_MySQL_快乐非自愿限量之名_InfoQ写作社区