SpringBoot 集成 Shiro

SpringBoot 集成 Shiro

1、框架搭建

​ 創建SpringBoot項目,集成Shiro組件。打開idea工具。進入File->New->Project選擇Spring Initializr

在這裏插入圖片描述

包命自己命名。項目創建好後,修改`pom.xml`文件,引入Shiro和Thymeleaf。pom.xml文件如下:
<?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.1.3.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>cn.org.july.shiro</groupId>
	<artifactId>springboot-shiro</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springboot-shiro</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<!-- 2 引入thymeleaf依賴 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>

		<!-- 3 引入shiro-spring 依賴-->
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>1.4.0</version>
		</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>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

2、 新建模版文件

​ 在resources目錄下新建templates文件夾,在templates文件夾中新建test.html文件和user文件夾,在user文件夾中新建add.html和updtae.html. 項目結構如下:

在這裏插入圖片描述

test.html 內容如下:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>測試Thymeleaf</title>
</head>
<body>
<h3 th:text="${test}"></h3>
<hr/>
進入用戶添加頁面:<a href="add">用戶添加</a>
<br>
進入用戶修改頁面:<a href="update">用戶修改</a>
</body>
</html>

add.html內容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用戶添加頁面</title>
</head>
<body>
<h1>用戶添加頁面</h1>
</body>
</html>

update.html 頁面內容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用戶修改頁面</title>
</head>
<body>
<h1>用戶修改頁面</h1>
</body>
</html>

​ 在項目中新增 UserController 包名自己起名即可。內容如下:

package cn.org.july.spring.shiro.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class UserController {

    @RequestMapping(value = "/hello")
    @ResponseBody
    public String hello() {
        return "ok";
    }
    @RequestMapping(value = "/testThymeleaf")
    public String testThymeleaf(Model model) {
        //把數據存入model
        model.addAttribute("test", "測試Thymeleaf");
        //返回test.html
        return "test";
    }

    @RequestMapping(value = "/add")
    public String add(Model model) {
        //把數據存入model
        model.addAttribute("test", "添加用戶頁面");
        //返回test.html
        return "/user/add";
    }
    
    @RequestMapping(value = "/update")
    public String update(Model model) {
        //把數據存入model
        model.addAttribute("test", "修改用戶頁面");
        //返回test.html
        return "/user/update";
    }
    
    @RequestMapping(value = "/toLogin")
    public String toLogin(){
        return "login";
    }
}

​ 啓動項目,訪問testThymeleaf頁面,在瀏覽器中輸入http://127.0.0.1:8080/testThymeleaf ,點擊兩個連接。效果如下圖:

在這裏插入圖片描述

3、配置Shiro

​ 在現有工程中新建兩個包分別是configrealm兩個包。在realm包中新建UserRealm類,該類實現用戶認證和權限授權。內容先簡單構建一下,

public class UserRealm extends AuthorizingRealm {
    /**
     * 執行授權邏輯
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.printf("用戶授權");
        return null;
    }

    /**
     * 執行認證邏輯
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.printf("用戶認證");
        return null;
    }
}

​ 在config包中新建ShiroConfig類。內容如下:

/**
 * shiro 的配置類
 */
@Configuration
public class ShiroConfig {
    /**
     * 創建shiroFilterFactoryBean
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //設置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        //配置Shiro過濾器
        /**
         * 內置Shiro過濾器實現相關攔截功能
         *      常用的過濾器有:
         *          anon  : 無需認證(登錄)可以訪問
         *          authc : 必須認證才能訪問
         *          user  : 如果使用rememberMe的功能可以直接訪問
         *          perms : 該資源必須得到資源訪問權限纔可以使用
         *          role  : 該資源必須得到角色授權纔可以使用
         */
        Map<String, String> filterMap = new LinkedHashMap<>();
        filterMap.put("/testThymeleaf", "anon");
        filterMap.put("/*", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        shiroFilterFactoryBean.setLoginUrl("/toLogin");
        return shiroFilterFactoryBean;
    }

    /**
     * 創建DefaultWebSecurityManager
     */
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    /**
     * 創建Realm
     */
    @Bean
    public UserRealm getRealm() {
        return new UserRealm();
    }

}

​ 配置完成後,啓動項目,訪問測試頁面,點擊添加用戶連接和修改用戶連接。效果如下圖。

在這裏插入圖片描述

​ 我們可以看到,當我們訪問用戶添加和用戶修改時,會跳轉到登錄頁面。我們配置的Shiro的訪問規則如下:

Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/testThymeleaf", "anon");// 不攔截測試頁面
filterMap.put("/*", "authc"); //攔截所有請求

​ 當我們點擊用戶添加和用戶修改時,Shiro攔截了我們的請求,通過設置shiroFilterFactoryBean.setLoginUrl("/toLogin");將攔截後的請求重定向到/toLogin頁面。

4、用戶認證

1、完善login.html頁面

​ 新增form表單,實現用戶名密碼登錄過程。完善後內容如下:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>登錄頁面</title>
</head>
<body>
<h1>登錄頁面</h1>
<hr/>
<h3 th:text="${msg}" style="color: red"></h3>
<form method="post" action="login">
    用戶名 :<input type="text" name="username"><br>
    密 碼 :<input type="password" name="password"><br>
    <input type="submit" value="登錄">
</form>
</body>
</html>

2、完善UserController

	新增`login`用戶登錄處理方法:
@RequestMapping(value = "/login")
    public String login(String username, String password, Model model) {
        System.out.printf("username :" + username);
        //1、獲取 Subject
        Subject subject = SecurityUtils.getSubject();
        //2、封裝用戶數據
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);
        //3、執行登錄方法
        try {
            subject.login(usernamePasswordToken);
            return "redirect:/testThymeleaf";
        } catch (UnknownAccountException e) {//該異常用戶名稱不存在
            //登錄失敗,用戶名稱不存在
            model.addAttribute("msg", "用戶名稱不存在");
            return "login";
        } catch (IncorrectCredentialsException e) {//該異常密碼錯誤
            //登錄失敗,密碼錯誤
            model.addAttribute("msg", "密碼錯誤");
            return "login";
        }
    }

3、修改UserRealm 完善用戶認證邏輯。

public class UserRealm extends AuthorizingRealm {
    /**
     * 執行授權邏輯
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.printf("用戶授權");
        return null;
    }

    /**
     * 執行認證邏輯
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("用戶認證開始");
        //1、模擬從數據庫獲取 用戶名稱和密碼
        String usernameByDB = "admin";
        String passwordByDb = "admin";

        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken;
        //2、判斷用戶名稱是否存在
        if (!usernameByDB.equals(usernamePasswordToken.getUsername())) {
            //用戶名稱不存在,Shiro底層會拋出UnknowAccountException
            return null;
        }
        //3、判斷密碼是否正確
        return new SimpleAuthenticationInfo("", passwordByDb, "");
    }
}

​ 注意:修改後檢查ShiroConfig中過濾規則是否對/login 請求開放,如沒有開放請求無法到達服務端。修改過濾規則。

Map<String, String> filterMap = new LinkedHashMap<>();
        filterMap.put("/testThymeleaf", "anon");
        filterMap.put("/login", "anon");
        filterMap.put("/*", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);

​ 修改完成後,重啓服務。

在這裏插入圖片描述

用戶認證功能完成。

5、整合Mybatis 完成用戶認證;

​ SpringBoot 整合Mybatis 建立數據庫連接,完善DAO,service 層見[Spring Cloud項目搭建] https://blog.csdn.net/July_whj/article/details/85476857 博客說明,不在此處詳細講解。

​ 修改UserRealm 將之前默認的用戶名稱密碼切換到數據庫。修改如下:

public class UserRealm extends AuthorizingRealm {
	//注入UserService
    @Autowired
    private UserService userService;

    /**
     * 執行授權邏輯
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.printf("用戶授權");
        return null;
    }

    /**
     * 執行認證邏輯
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("用戶認證開始");

        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken;
        //根據用戶名稱查看用戶信息
        User user = userService.findUserByName(usernamePasswordToken.getUsername());
        //2、判斷用戶名稱是否存在
        if (null == user || !user.getUserName().equals(usernamePasswordToken.getUsername())) {
            //用戶名稱不存在,Shiro底層會拋出UnknowAccountException
            return null;
        }
        //3、判斷密碼是否正確
        return new SimpleAuthenticationInfo("", user.getPassword(), "");
    }
}

效果如下:

在這裏插入圖片描述

6、資源授權

1、新增資源訪問權限配置

​ 修改ShiroConfig 新增資源訪問權限。

/**
 * 授權資源
 */
        filterMap.put("/add", "perms[user:add]");//訪問 /add時需要user:add的權限
        filterMap.put("/*", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");//如果沒權限跳轉到/noAuth請求
        shiroFilterFactoryBean.setLoginUrl("/toLogin");

2、新增noAuth.html 頁面,如果沒有權限訪問,跳轉至該頁面。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>授權失敗</title>
</head>
<body>
<h1>沒有權限,無法訪問該頁面。</h1>
</body>
</html>	

​ 重啓服務後訪問如下:

在這裏插入圖片描述

3、使用shiro標籤控制前臺顯示控件

​ 1、新增pom依賴,thymeleaf 擴展 shiro

<!-- thymeleaf 擴展 shiro-->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

​ 2、修改ShiroConfig 配置

配置ShiroDialect, 用於thymeleaf和Shiro標籤配置使用。新增如下配置:

/**
     * 配置ShiroDialect, 用於thymeleaf和Shiro標籤配置使用
     */
    @Bean
    public ShiroDialect getShiroDialect() {
        return new ShiroDialect();
    }

​ 3、修改test.html,新增Shiro標籤

​ 在test.html 中新增 <div>標籤,並使用shiro:hasPermission該標籤,判斷當前登錄用戶是否有該權限。沒有權限則隱藏該控件。

<!DOCTYPE html> 
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml" xmlns:shiro="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>測試Thymeleaf</title>
</head>
<body>
<h3 th:text="${test}"></h3>
<hr/>
<div shiro:hasPermission="user:add">
    進入用戶添加頁面:<a href="add">用戶添加</a>
</div>
<br>
<div shiro:hasPermission="user:update">
    進入用戶修改頁面:<a href="update">用戶修改</a>
</div>
</body>
</html>

​ 4、修改UserRealm類,修改用戶授權

​ 修改授權類,獲取當前登錄用戶權限,並賦值給Shiro。進行權限判定。獲取當前登錄用戶通過doGetAuthenticationInfo方法,如果用戶登錄成功則將用戶通過SimpleAuthenticationInfo對象賦值給Subject對象中principal 屬性。我們可以通過以下方法獲取當前登錄用戶信息,並將權限賦值給Shiro。

/**
     * 執行授權邏輯
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.printf("用戶授權");
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipal();
        simpleAuthorizationInfo.addStringPermission(user.getPerms());
        return simpleAuthorizationInfo;
    }

​ 系統重啓,訪問瀏覽器,效果如下:

在這裏插入圖片描述

附錄:數據庫腳本

/*
 Navicat MySQL Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 50719
 Source Host           : localhost
 Source Database       : cloudDB01

 Target Server Type    : MySQL
 Target Server Version : 50719
 File Encoding         : utf-8

 Date: 03/03/2019 21:24:28 PM
*/

SET NAMES utf8;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
--  Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userName` varchar(50) DEFAULT NULL,
  `dbSource` varchar(50) DEFAULT NULL,
  `phone` varchar(20) DEFAULT NULL,
  `email` varchar(50) DEFAULT NULL,
  `password` varchar(50) DEFAULT NULL,
  `perms` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;

-- ----------------------------
--  Records of `user`
-- ----------------------------
BEGIN;
INSERT INTO `user` VALUES ('1', 'JULY', 'cloudDB01', '18232533234', '[email protected]', '123456', 'user:add'), ('2', 'WHJ', 'cloudDB01', '12312312312', '[email protected]', '123456', 'user:update');
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;

項目源碼地址:https://github.com/hongjieWang/SpringBoot-Shiro/tree/master/code/springboot-shiro
Shiro 視頻地址:https://download.csdn.net/download/july_whj/10991709

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章