Springboot+Shiro+Mybatis+mysql實(shí)現(xiàn)權(quán)限安全認(rèn)證的示例代碼
Shiro是Apache 的一個(gè)強(qiáng)大且易用的Java安全框架,執(zhí)行身份驗(yàn)證、授權(quán)、密碼學(xué)和會(huì)話管理。Shiro 主要分為兩個(gè)部分就是認(rèn)證和授權(quán)兩部分
一、介紹
- Subject代表了當(dāng)前用戶的安全操作
- SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通過SecurityManager來管理內(nèi)部組件實(shí)例,并通過它來提供安全管理的各種服務(wù)。
- Authenticator即認(rèn)證器,對(duì)用戶身份進(jìn)行認(rèn)證,Authenticator是一個(gè)接口,shiro提供ModularRealmAuthenticator實(shí)現(xiàn)類,通過ModularRealmAuthenticator基本上可以滿足大多數(shù)需求,也可以自定義認(rèn)證器。
- Authorizer即授權(quán)器,用戶通過認(rèn)證器認(rèn)證通過,在訪問功能時(shí)需要通過授權(quán)器判斷用戶是否有此功能的操作權(quán)限。
- Realm充當(dāng)了Shiro與應(yīng)用安全數(shù)據(jù)間的“橋梁”或者“連接器”。也就是說,當(dāng)對(duì)用戶執(zhí)行認(rèn)證(登錄)和授權(quán)(訪問控制)驗(yàn)證時(shí),Shiro會(huì)從應(yīng)用配置的Realm中查找用戶及其權(quán)限信息。
- sessionManager即會(huì)話管理,shiro框架定義了一套會(huì)話管理,它不依賴web容器的session,所以shiro可以使用在非web應(yīng)用上。
Shiro相關(guān)類介紹
- (1)Authentication 認(rèn)證 —— 用戶登錄
- (2)Authorization 授權(quán) —- 用戶具有哪些權(quán)限
- (3)Cryptography 安全數(shù)據(jù)加密
- (4)Session Management 會(huì)話管理
- (5)Web Integration web系統(tǒng)集成
- (6)Interations 集成其它應(yīng)用,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> <!-- 排除默認(rèn)的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配置文件: # 開發(fā)時(shí)關(guān)閉緩存,不然沒法看到實(shí)時(shí)頁面 spring.thymeleaf.cache=false # 用非嚴(yán)格的 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導(dǎo)入包不和以前一樣 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 #打印數(shù)據(jù)庫的操作 logging.level.com.example.springsecurity.dao=debug #redis緩存 ### 配置Redis mybatis.configuration.cache-enabled=true # Redis數(shù)據(jù)庫索引(默認(rèn)為0) spring.redis.database=0 # Redis服務(wù)器地址 spring.redis.host=... # Redis服務(wù)器連接端口 spring.redis.port=6379 # Redis服務(wù)器連接密碼(默認(rèn)為空) spring.redis.password=sunyue # 連接池最大連接數(shù)(使用負(fù)值表示沒有限制) spring.redis.jedis.pool.max-idle=200 # 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒有限制) spring.redis.jedis.pool.max-wait=-1 # 連接池中的最小空閑連接 spring.redis.jedis.pool.min-idle=0 # 連接超時(shí)時(shí)間(毫秒) spring.redis.timeout=1000
Shiro兩個(gè)重要的配置類:
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; /** * 執(zhí)行授權(quán)邏輯 * * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("執(zhí)行授權(quán)邏輯"); /*獲取當(dāng)前登錄的用戶信息*/ Subject subject = SecurityUtils.getSubject(); TestUser testUser = (TestUser) subject.getPrincipal(); //設(shè)置角色,多個(gè)角色 /*Set<String> rolesSet = new HashSet<>(); rolesSet.add(testUser.getRole());*/ //SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(rolesSet); //給資源進(jìn)行授權(quán) SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); /*可以在以下list加入多個(gè)權(quán)限*/ /*List<String> roles = new ArrayList<>(); roles.add(testUser.getPerms()); info.addRoles(roles);*/ //設(shè)置權(quán)限 info.addRole(testUser.getRole()); //需要判斷權(quán)限是否為空值(null是沒有地址,""是有地址但是里面的內(nèi)容是空的) if (testUser.getPerms() != null && !testUser.getPerms().equals("")) { info.addStringPermission(testUser.getPerms()); } return info; } /** * 執(zhí)行認(rèn)證邏輯 * * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("執(zhí)行認(rèn)證邏輯"); /*獲取令牌*/ UsernamePasswordToken passwordToken = (UsernamePasswordToken) authenticationToken; //取出用戶名并且判斷用戶名是否和數(shù)據(jù)庫一致 TestUser testUser = testUserServer.selectOneByName(passwordToken.getUsername()); if (testUser != null) { //進(jìn)行認(rèn)證,將正確數(shù)據(jù)給shiro處理 //密碼不用自己比對(duì),AuthenticationInfo認(rèn)證信息對(duì)象,一個(gè)接口,new他的實(shí)現(xiàn)類對(duì)象SimpleAuthenticationInfo /* 第一個(gè)參數(shù)隨便放,可以放user對(duì)象,程序可在任意位置獲取 放入的對(duì)象 * 第二個(gè)參數(shù)必須放密碼, * 第三個(gè)參數(shù)放 當(dāng)前realm的名字,因?yàn)榭赡苡卸鄠€(gè)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(); //設(shè)置安全管理器 shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager); //添加一些Shiro的內(nèi)置過濾器 /** * Shiro 的內(nèi)置過濾器可以實(shí)現(xiàn)權(quán)限的相關(guān)攔截 * 常用過濾器 * 1.anon:無需認(rèn)證 * 2.authc:必須認(rèn)證才能訪問 * 3.user:如果使用rememberme功能可以訪問 * 4.perms:對(duì)應(yīng)權(quán)限才能訪問 * 5.role:對(duì)應(yīng)角色才能訪問 */ //登錄狀態(tài)下才可以訪問main頁面,manage權(quán)限可訪問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); //未登錄狀態(tài)下訪問將跳轉(zhuǎn)至login頁面 // 如果不設(shè)置默認(rèn)會(huì)自動(dòng)尋找Web工程根目錄下的"/login.jsp"頁面 shiroFilterFactoryBean.setLoginUrl("/login"); // 登錄成功后要跳轉(zhuǎn)的鏈接 shiroFilterFactoryBean.setSuccessUrl("/"); //無授限狀態(tài)下訪問將請(qǐng)求unauthor shiroFilterFactoryBean.setUnauthorizedUrl("/unAuth"); return shiroFilterFactoryBean; } @Bean(name = "securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) { DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(); //DefaultWebSecurityManager需要關(guān)聯(lián)一個(gè)Realm defaultWebSecurityManager.setRealm(userRealm); return defaultWebSecurityManager; } /** * 創(chuàng)建realm */ @Bean(name = "userRealm") public UserRealm getRealm() { return new UserRealm(); } @Bean public ShiroDialect shiroDialect() { return new ShiroDialect(); } /** * 開啟Shiro的注解(如@RequiresRoles,@RequiresPermissions) * 配置以下兩個(gè)bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)即可實(shí)現(xiàn)此功能 * * @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出現(xiàn)權(quán)限異??赏ㄟ^此異常實(shí)現(xiàn)制定頁面的跳轉(zhuǎn)(或接口跳轉(zhuǎn)) * * @return */ @Bean public SimpleMappingExceptionResolver simpleMappingExceptionResolver() { SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver(); Properties properties = new Properties(); /*未授權(quán)處理頁*/ properties.setProperty("org.apache.shiro.authz.UnauthorizedException", "/error.html"); /*身份沒有驗(yàn)證*/ properties.setProperty("org.apache.shiro.authz.UnauthenticatedException", "/error.html"); resolver.setExceptionMappings(properties); return resolver; } }
四、數(shù)據(jù)連接和業(yè)務(wù)邏輯
1.實(shí)體類
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; /*權(quán)限*/ 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.業(yè)務(wù)層及其實(shí)現(xiàn)
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(); /*查詢一個(gè)用戶*/ TestUser selectByOne(Integer id); /*通過名字查詢一個(gè)用戶*/ TestUser selectOneByName(String name); /*增加一個(gè)用戶*/ void insert(TestUser testUser); /*刪除一個(gè)用戶*/ void delete(Integer id); /*更新一個(gè)用戶*/ 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) { //根據(jù)salt值和用戶輸入的密碼計(jì)算加密后的密碼 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進(jìn)行認(rèn)證 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 "權(quán)限不足,無法訪問"; } @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="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" /> </head> <body> <div th:if="${session.testUser != null}"> <span th:text="'歡迎回來 '+${session.testUser.username}+'! '"> </span><a href="/logout" rel="external nofollow" >退出</a> </div> <a href="/main" rel="external nofollow" >main</a> <span shiro:hasPermission="manage"> | <a href="/manage" rel="external nofollow" >manage</a></span> <span shiro:hasRole="admin"> | <a href="/admin" rel="external nofollow" >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="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" /> </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" rel="external nofollow" > <button type="button" value="注冊(cè)">注冊(cè)</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="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" /> </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="注冊(cè)"/></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="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" /> </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="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" /> </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="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" /> </head> <body> <h1>admin</h1> </body> </html>
6.數(shù)據(jù)庫文件
/* 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);
到此這篇關(guān)于Springboot+Shiro+Mybatis+mysql實(shí)現(xiàn)權(quán)限安全認(rèn)證的文章就介紹到這了,更多相關(guān)Springboot Shiro Mybatis mysql權(quán)限安全認(rèn)證內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot+Shiro+Redis+Mybatis-plus 實(shí)戰(zhàn)項(xiàng)目及問題小結(jié)
- 解決springboot+shiro 權(quán)限攔截失效的問題
- Springboot和bootstrap實(shí)現(xiàn)shiro權(quán)限控制配置過程
- SpringBoot + Shiro前后端分離權(quán)限
- SpringBoot 整合 Shiro 密碼登錄與郵件驗(yàn)證碼登錄功能(多 Realm 認(rèn)證)
- Springboot shiro認(rèn)證授權(quán)實(shí)現(xiàn)原理及實(shí)例
- 基于springboot實(shí)現(xiàn)整合shiro實(shí)現(xiàn)登錄認(rèn)證以及授權(quán)過程解析
- SpringBoot整合Shiro實(shí)現(xiàn)登錄認(rèn)證的方法
相關(guān)文章
SpringBoot多數(shù)據(jù)源讀寫分離的自定義配置問題及解決方法
這篇文章主要介紹了SpringBoot多數(shù)據(jù)源讀寫分離的自定義配置,我們可以通過自定義配置數(shù)據(jù)庫配置類來解決這個(gè)問題,方式有很多,不同的業(yè)務(wù)采用的方式也不同,下面我簡單的介紹我們項(xiàng)目的使用的方法2022-06-06使用SpringBoot + Redis + Vue實(shí)現(xiàn)動(dòng)態(tài)路由加載頁面的示例代
在現(xiàn)代 Web 應(yīng)用開發(fā)中,動(dòng)態(tài)路由加載能夠顯著提升應(yīng)用的靈活性和安全性,本文將深入探討如何利用 Spring Boot、Redis、Element UI 和 Vue 技術(shù)棧實(shí)現(xiàn)動(dòng)態(tài)路由加載,并通過 Redis 生成和驗(yàn)證有效鏈接以實(shí)現(xiàn)頁面訪問控制,需要的朋友可以參考下2024-09-09idea快速找到項(xiàng)目中對(duì)應(yīng)的類圖文詳解(包括源碼)
用IDEA開發(fā)Java項(xiàng)目時(shí)經(jīng)常會(huì)使用到各種快捷鍵,其中搜索是最常用的之一,下面這篇文章主要給大家介紹了關(guān)于idea如何快速找到項(xiàng)目中對(duì)應(yīng)的類(包括源碼)的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06Java并發(fā)工具類Exchanger的相關(guān)知識(shí)總結(jié)
今天給大家?guī)淼奈恼率荍ava工具類Exchanger的相關(guān)知識(shí)總結(jié),文中有非常詳細(xì)的介紹及代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們很有幫助,需要的朋友可以參考下2021-06-06新手初學(xué)Java對(duì)象內(nèi)存構(gòu)成
這篇文章主要介紹了深入理解JVM之Java對(duì)象的創(chuàng)建、內(nèi)存布局、訪問定位,結(jié)合實(shí)例形式詳細(xì)分析了Java對(duì)象的創(chuàng)建、內(nèi)存布局、訪問定位相關(guān)概念、原理、操作技巧與注意事項(xiàng),需要的朋友可以參考下2021-07-07springboot+EHcache 實(shí)現(xiàn)文章瀏覽量的緩存和超時(shí)更新
這篇文章主要介紹了springboot+EHcache 實(shí)現(xiàn)文章瀏覽量的緩存和超時(shí)更新,問題描述和解決思路給大家介紹的非常詳細(xì),需要的朋友可以參考下2017-04-04Java基于Socket實(shí)現(xiàn)多人聊天室
這篇文章主要為大家詳細(xì)介紹了Java基于Socket實(shí)現(xiàn)多人聊天室,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-09-09JavaWeb實(shí)現(xiàn)裁剪圖片上傳完整代碼
這篇文章主要為大家詳細(xì)介紹了javaWeb實(shí)現(xiàn)裁剪圖片上傳完整代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09