文章大綱
一、權限框架介紹
二、Shiro基礎介紹
三、Spring Boot整合Shiro代碼實戰
四、項目源碼與資料下載
五、參考文章

一、權限框架介紹
1. 什么是權限管理
權限管理屬於系統安全的范疇,權限管理實現對用戶訪問系統的控制,按照安全規則或者安全策略控制用戶可以訪問而且只能訪問自己被授權的資源。
權限管理包括用戶身份認證和授權兩部分,簡稱認證授權。對於需要訪問控制的資源用戶首先經過身份認證,認證通過后用戶具有該資源的訪問權限方可訪問。
1.1 用戶身份認證
身份認證,就是判斷一個用戶是否為合法用戶的處理過程。最常用的簡單身份認證方式是系統通過核對用戶輸入的用戶名和口令,看其是否與系統中存儲的該用戶的用戶名和口令一致,來判斷用戶身份是否正確。對於采用指紋等系統,則出示指紋;對於硬件Key等刷卡系統,則需要刷卡。
用戶名密碼身份認證流程:

1.2 授權流程
授權,即訪問控制,控制誰能訪問哪些資源。主體進行身份認證后需要分配權限方可訪問系統的資源,對於某些資源沒有權限是無法訪問的。

2. 常見權限框架
2.1 Shiro簡介
Apache Shiro是Java的一個安全框架。目前,使用Apache Shiro的人越來越多,因為它相當簡單,對比Spring Security,可能沒有Spring Security做的功能強大,但是在實際工作時可能並不需要那么復雜的東西,所以使用小而簡單的Shiro就足夠了。對於它倆到底哪個好,這個不必糾結,能更簡單的解決項目問題就好了。
2.2 Spring Security
Spring Security是一個能夠為基於Spring的企業應用系統提供聲明式的安全訪問控制解決方案的安全框架。它提供了一組可以在Spring應用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反轉Inversion of Control ,DI:Dependency Injection 依賴注入)和AOP(面向切面編程)功能,為應用系統提供聲明式的安全訪問控制功能,減少了為企業系統安全控制編寫大量重復代碼的工作。它是一個輕量級的安全框架,它確保基於Spring的應用程序提供身份驗證和授權支持。它與Spring MVC有很好地集成,並配備了流行的安全算法實現捆綁在一起。安全主要包括兩個操作“認證”與“驗證”(有時候也會叫做權限控制)。“認證”是為用戶建立一個其聲明的角色的過程,這個角色可以一個用戶、一個設備或者一個系統。“驗證”指的是一個用戶在你的應用中能夠執行某個操作。在到達授權判斷之前,角色已經在身份認證過程中建立了。
2.3 Shiro和Spring Security比較
(1)Shiro比Spring更容易使用,實現和最重要的理解
(2)Spring Security更加知名的唯一原因是因為品牌名稱
(3)“Spring”以簡單而聞名,但諷刺的是很多人發現安裝Spring Security很難
(4)Spring Security卻有更好的社區支持
(5)Apache Shiro在Spring Security處理密碼學方面有一個額外的模塊
(6)Spring-security 對spring 結合較好,如果項目用的springmvc ,使用起來很方便。但是如果項目中沒有用到spring,那就不要考慮它了。
(7)Shiro 功能強大、且 簡單、靈活。是Apache 下的項目比較可靠,且不跟任何的框架或者容器綁定,可以獨立運行
二、Shiro基礎介紹
1. Shiro三個核心組件
1.1 Subject
Subject:即“當前操作用發戶”。但是,在Shiro中,Subject這一概念並不僅僅指人,也可以是第三方進程、后台帳戶(Daemon Account)或其他類似事物。它僅僅意味着“當前跟軟件交互的東西”。但考慮到大多數目的和用途,你可以把它認為是Shiro的“用戶”概念。Subject代表了當前用戶的安全操作,SecurityManager則管理所有用戶的安全操作。
1.2 SecurityManager
SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通過SecurityManager來管理內部組件實例,並通過它來提供安全管理的各種服務。
1.3 Realm
Realm充當了Shiro與應用安全數據間的“橋梁”或者“連接器”。也就是說,當對用戶執行認證(登錄)和授權(訪問控制)驗證時,Shiro會從應用配置的Realm中查找用戶及其權限信息。
從這個意義上講,Realm實質上是一個安全相關的DAO:它封裝了數據源的連接細節,並在需要時將相關數據提供給Shiro。當配置Shiro時,你必須至少指定一個Realm,用於認證和(或)授權。配置多個Realm是可以的,但是至少需要一個。
Shiro內置了可以連接大量安全數據源(又名目錄)的Realm,如LDAP、關系數據庫(JDBC)、類似INI的文本配置資源以及屬性文件等。如果缺省的Realm不能滿足需求,你還可以插入代表自定義數據源的自己的Realm實現。
2. Shiro相關類介紹
(1)Authentication 認證 ---- 用戶登錄
(2)Authorization 授權 --- 用戶具有哪些權限
(3)Cryptography 安全數據加密
(4)Session Management 會話管理
(5)Web Integration web系統集成
(6)Interations 集成其它應用,spring、緩存框架
3. Shiro 特點
(1)易於理解的 Java Security API;
(2)簡單的身份認證(登錄),支持多種數據源(LDAP,JDBC,Kerberos,ActiveDirectory 等);
(3)對角色的簡單的簽權(訪問控制),支持細粒度的簽權;
(4)支持一級緩存,以提升應用程序的性能;
(5)內置的基於 POJO 企業會話管理,適用於 Web 以及非 Web 的環境;
(6)異構客戶端會話訪問;
(7)非常簡單的加密 API;
(8)不跟任何的框架或者容器捆綁,可以獨立運行
三、Spring Boot整合Shiro代碼實戰
1. Spring Boot基礎
https://www.cnblogs.com/WUXIAOCHANG/p/10877266.html
2. 創建Spring Boot的基礎項目
2.1 新建maven項目



創建后項目結構如下:

2.2 pom.xml中添加依賴
<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> <!-- 繼承Spring Boot的默認父工程 --> <!-- Spring Boot 父工程 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.4.RELEASE</version> </parent> <groupId>com.itheima</groupId> <artifactId>springboot-shiro</artifactId> <version>0.0.1-SNAPSHOT</version> <!-- 導入依賴 --> <dependencies> <!-- 導入web支持:SpringMVC開發支持,Servlet相關的程序 --> <!-- web支持,SpringMVC, Servlet支持等 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <!-- 修改參數 --> <properties> <!-- 修改JDK的編譯版本為1.8 --> <java.version>1.8</java.version> </properties> </project>
2.3 編寫測試Controller類
com.itheima.controller包下新建UserController.java
package com.itheima.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class UserController { /** * 測試方法 */ @RequestMapping("/hello") @ResponseBody public String hello(){ System.out.println("UserController.hello()"); return "ok"; } }
2.4 導入thymeleaf頁面模塊
pom.xml文件中添加依賴
<!-- 導入thymeleaf依賴 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
UserController.java類中添加測試方法
/** * 測試thymeleaf */ @RequestMapping("/testThymeleaf") public String testThymeleaf(Model model){ //把數據存入model model.addAttribute("name", "吳先生"); //返回test.html return "test"; }
2.5 添加thymeleaf頁面模塊
在src/main/resource目錄下創建templates目錄,然后創建test.html頁面
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>測試Thymeleaf的使用</title> </head> <body> <h3 th:text="${name}"></h3> </body> </html>

2.6 運行項目並訪問
運行項目

訪問項目


3. Spring Boot與Shiro整合實現用戶認證
3.1 分析Shiro的核心API
Subject: 用戶主體(把操作交給SecurityManager)
SecurityManager:安全管理器(關聯Realm)
Realm:Shiro連接數據的橋梁
3.2 導入shiro與spring整合依賴
pom.xml文件中添加依賴
<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> <!-- 繼承Spring Boot的默認父工程 --> <!-- Spring Boot 父工程 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.4.RELEASE</version> </parent> <groupId>com.itheima</groupId> <artifactId>springboot-shiro</artifactId> <version>0.0.1-SNAPSHOT</version> <!-- 導入依賴 --> <dependencies> <!-- 導入web支持:SpringMVC開發支持,Servlet相關的程序 --> <!-- web支持,SpringMVC, Servlet支持等 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 導入thymeleaf依賴 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!-- shiro與spring整合依賴 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency> <!-- 導入mybatis相關的依賴 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.9</version> </dependency> <!-- mysql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- SpringBoot的Mybatis啟動器 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.1.1</version> </dependency> <!-- thymel對shiro的擴展坐標 --> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency> </dependencies> <!-- 修改參數 --> <properties> <!-- 修改JDK的編譯版本為1.8 --> <java.version>1.8</java.version> <!-- 修改thymeleaf的版本 --> <thymeleaf.version>3.0.2.RELEASE</thymeleaf.version> <thymeleaf-layout-dialect.version>2.0.4</thymeleaf-layout-dialect.version> </properties> <build> <!--解決項目運行后mapper.xmlw文件找不到情況--> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> </resources> </build> </project>
3.3 resources下配置
新建application.properties文件
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/shiro_test spring.datasource.username=root spring.datasource.password=147258qq spring.datasource.type=com.alibaba.druid.pool.DruidDataSource mybatis.type-aliases-package=com.itheima.domain
templates文件夾下加入相關模板頁面
add.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>用戶添加頁面</title> </head> <body> 用戶添加 </body> </html>
update.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>用戶更新頁面</title> </head> <body> 用戶更新 </body> </html>
login.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登錄頁面</title> </head> <body> <h3>登錄</h3> <h3 th:text="${msg}" style="color: red"></h3> <form method="post" action="login"> 用戶名:<input type="text" name="name"/><br/> 密碼:<input type="password" name="password"/><br/> <input type="submit" value="登錄"/> </form> </body> </html>
noAuth.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>未授權提示頁面</title> </head> <body> 親,你未經授權訪問該頁面 </body> </html>

3.4 新建shiro相關配置
com.itheima.shiro包下新建ShiroConfig.java類
package com.itheima.shiro; import java.util.LinkedHashMap; import java.util.Map; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; /** * Shiro的配置類 * * 關於Configuration的講解,可參考一下博客:https://www.cnblogs.com/WUXIAOCHANG/p/10877266.html * @author lenovo * */ @Configuration public class ShiroConfig { /** * 創建ShiroFilterFactoryBean */ @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){ ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //設置安全管理器 shiroFilterFactoryBean.setSecurityManager(securityManager); //添加Shiro內置過濾器 /** * Shiro內置過濾器,可以實現權限相關的攔截器 * 常用的過濾器: * anon: 無需認證(登錄)可以訪問 * authc: 必須認證才可以訪問 * user: 如果使用rememberMe的功能可以直接訪問 * perms: 該資源必須得到資源權限才可以訪問 * role: 該資源必須得到角色權限才可以訪問 */ Map<String,String> filterMap = new LinkedHashMap<String,String>(); /*filterMap.put("/add", "authc"); filterMap.put("/update", "authc");*/ filterMap.put("/testThymeleaf", "anon"); //放行login.html頁面 filterMap.put("/login", "anon"); //授權過濾器 //注意:當前授權攔截后,shiro會自動跳轉到未授權頁面 //perms括號中的內容是權限的值 filterMap.put("/add", "perms[user:add]"); filterMap.put("/update", "perms[user:update]"); filterMap.put("/*", "authc"); //修改調整的登錄頁面 shiroFilterFactoryBean.setLoginUrl("/toLogin"); //設置未授權提示頁面 shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); return shiroFilterFactoryBean; } /** * 創建DefaultWebSecurityManager * * 里面主要定義了登錄,創建subject,登出等操作 */ @Bean(name="securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //關聯realm securityManager.setRealm(userRealm); return securityManager; } /** * 創建Realm */ @Bean(name="userRealm") public UserRealm getRealm(){ return new UserRealm(); } /** * 配置ShiroDialect,用於thymeleaf和shiro標簽配合使用 */ @Bean public ShiroDialect getShiroDialect(){ return new ShiroDialect(); } }
com.itheima.shiro包下新建UserRealm.java類
package com.itheima.shiro; import org.apache.shiro.SecurityUtils; 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.authc.UsernamePasswordToken; 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 com.itheima.domain.User; import com.itheima.service.UserService; /** * 自定義Realm * (1)AuthenticatingRealm:shiro中的用於進行認證的領域,實現doGetAuthentcationInfo方法實現用戶登錄時的認證邏輯; * (2)AuthorizingRealm:shiro中用於授權的領域,實現doGetAuthrozitionInfo方法實現用戶的授權邏輯,AuthorizingRealm繼承了AuthenticatingRealm, * 所以在實際使用中主要用到的就是這個AuthenticatingRealm類; * (3)AuthenticatingRealm、AuthorizingRealm這兩個類都是shiro中提供了一些線程的realm接口 * (4)在與spring整合項目中,shiro的SecurityManager會自動調用這兩個方法,從而實現認證和授權,可以結合shiro的CacheManager將認證和授權信息保存在緩存中, * 這樣可以提高系統的處理效率。 * */ public class UserRealm extends AuthorizingRealm{ @Autowired private UserService userSerivce; /** * 執行認證邏輯 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException { System.out.println("執行認證邏輯"); //編寫shiro判斷邏輯,判斷用戶名和密碼 //1.判斷用戶名 token中的用戶信息是登錄時候傳進來的 UsernamePasswordToken token = (UsernamePasswordToken)arg0; User user = userSerivce.findByName(token.getUsername()); if(user==null){ //用戶名不存在 return null;//shiro底層會拋出UnKnowAccountException } //2.判斷密碼 //第二個字段是user.getPassword(),注意這里是指從數據庫中獲取的password。第三個字段是realm,即當前realm的名稱。 //這塊對比邏輯是先對比username,但是username肯定是相等的,所以真正對比的是password。 //從這里傳入的password(這里是從數據庫獲取的)和token(filter中登錄時生成的)中的password做對比,如果相同就允許登錄, // 不相同就拋出IncorrectCredentialsException異常。 //如果認證不通過,就不會執行下面的授權方法了 return new SimpleAuthenticationInfo(user,user.getPassword(),""); } /** * 執行授權邏輯 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) { //doGetAuthorizationInfo方法可能會執行多次,權限判斷次數多少,就會執行多少次 System.out.println("執行授權邏輯1"); System.out.println("執行授權邏輯2"); //給資源進行授權 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //添加資源的授權字符串 //info.addStringPermission("user:add"); //到數據庫查詢當前登錄用戶的授權字符串 //獲取當前登錄用戶 Subject subject = SecurityUtils.getSubject(); User user = (User)subject.getPrincipal(); User dbUser = userSerivce.findById(user.getId()); info.addStringPermission(dbUser.getPerms()); return info; } }
3.5 新建實體類
com.itheima.domain包下新建User.java
package com.itheima.domain; public class User { private Integer id; private String name; private String password; private String perms; public String getPerms() { return perms; } public void setPerms(String perms) { this.perms = perms; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
3.6 創建mapper相關內容
com.itheima.mapper包下新建UserMapper.java
package com.itheima.mapper; import com.itheima.domain.User; public interface UserMapper { public User findByName(String name); public User findById(Integer id); }
com.itheima.mapper包下新建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"> <!-- 該文件存放CRUD的sql語句 --> <mapper namespace="com.itheima.mapper.UserMapper"> <select id="findByName" parameterType="string" resultType="user"> SELECT id, NAME, PASSWORD FROM user where name = #{value} </select> <select id="findById" parameterType="int" resultType="user"> SELECT id, NAME, PASSWORD, perms FROM user where id = #{value} </select> </mapper>
3.7 創建業務邏輯相關內容
com.itheima.service下新建UserService.java
package com.itheima.service; import com.itheima.domain.User; public interface UserService { public User findByName(String name); public User findById(Integer id); }
com.itheima.service.impl下新建UserServiceImpl.java
package com.itheima.service.impl; import org.apache.tomcat.util.net.openssl.ciphers.Authentication; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.itheima.domain.User; import com.itheima.mapper.UserMapper; import com.itheima.service.UserService; @Service public class UserServiceImpl implements UserService{ //注入Mapper接口 @Autowired private UserMapper userMapper; @Override public User findByName(String name) { return userMapper.findByName(name); } @Override public User findById(Integer id) { return userMapper.findById(id); } }
3.8 新建Controller相關內容
UserController.java添加相關代碼,最終內容如下:
package com.itheima.controller; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; 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.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.itheima.service.UserService; @Controller public class UserController { /** * 測試方法 */ @RequestMapping("/hello") @ResponseBody public String hello(){ System.out.println("UserController.hello()"); return "ok"; } @RequestMapping("/add") public String add(){ return "/user/add"; } @RequestMapping("/update") public String update(){ return "/user/update"; } @RequestMapping("/toLogin") public String toLogin(){ return "/login"; } @RequestMapping("/noAuth") public String noAuth(){ return "/noAuth"; } /** * 測試thymeleaf */ @RequestMapping("/testThymeleaf") public String testThymeleaf(Model model){ //把數據存入model model.addAttribute("name", "吳先生"); //返回test.html return "test"; } /** * 登錄邏輯處理 */ @RequestMapping("/login") public String login(String name,String password,Model model){ System.out.println("name="+name); /** * 使用Shiro編寫認證操作 */ //1.獲取Subject Subject subject = SecurityUtils.getSubject(); //2.封裝用戶數據 UsernamePasswordToken token = new UsernamePasswordToken(name,password); //3.執行登錄方法 try { subject.login(token); //登錄成功 //跳轉到test.html return "redirect:/testThymeleaf"; } catch (UnknownAccountException e) { //e.printStackTrace(); //登錄失敗:用戶名不存在,UnknownAccountException是Shiro拋出的找不到用戶異常 model.addAttribute("msg", "用戶名不存在"); return "login"; }catch (IncorrectCredentialsException e) { //e.printStackTrace(); //登錄失敗:密碼錯誤,IncorrectCredentialsException是Shiro拋出的密碼錯誤異常 model.addAttribute("msg", "密碼錯誤"); return "login"; } } }
3.9 Application啟動類配置
package com.itheima; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * SpringBoot啟動類 * @author lenovo * */ @SpringBootApplication //之前是,直接在Mapper類上面添加注解@Mapper,這種方式要求每一個mapper類都需要添加此注解,麻煩 //通過使用@MapperScan可以指定要掃描的Mapper類的包的路徑 同時,使用@MapperScan注解多個包 @MapperScan("com.itheima.mapper") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
3.10 創建后項目結構

3.11 數據庫配置
數據庫的sql文件可以在項目源碼與資料下載中獲取,我們創建的數據庫名字為shiro_test,具體字段參數如下圖所示:

往數據庫插入一條數據

3.12 運行項目並訪問

訪問http://localhost:8080/add或者http://localhost:8080/update,可以看到被攔截了,重定向到了登錄頁面


訪問http://localhost:8080/login,進行登錄

登錄成功

我們在數據庫添加的權限是修改的,我們試試登錄后,訪問添加頁面

可以看到,已經被攔截了
四、項目源碼與資料下載
鏈接:https://pan.baidu.com/s/12yTMozR6oFG6cYcVmnBwog
提取碼:yswz