SpringBoot整合Shiro(含GIF效果展示哦)

1. 環境的基本搭建

這裏的類似什麼啓動類,頁面跳轉的之間的代碼這裏我就省略啦,直接寫shiro的配置類.如果對詳細信息想了解的話,請參考代碼連接,項目的下載地址爲:
鏈接:https://pan.baidu.com/s/1Rxubu_XgDoehuAc0uESyaQ
提取碼:2kau

1.項目依賴

<?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>

    <groupId>com.tvu</groupId>
    <artifactId>SpringBoot-Shrio</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 繼承Spring Boot的默認父工程 -->
    <!-- Spring Boot 父工程 -->


    <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>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.RELEASE</version>
    </parent>
    <dependencies>
        <!-- 導入web支持:SpringMVC開發支持,Servlet相關的程序 -->
        <!-- web支持,SpringMVC, Servlet支持等 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>

    </dependencies>



</project>

2.配置類
基礎的配置類

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 java.util.HashMap;

@Configuration
public class ShiroConfig {

    /**
     * 創建ShiroFilterFactoryBean
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        return shiroFilterFactoryBean;
    }

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

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

簡單的基礎邏輯

package com.bwie.shrio;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

public class UserRealm extends AuthorizingRealm {

    /**
     * 執行授權邏輯
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
        System.out.println("執行授權邏輯");
        return null;
    }

    /**
     * 執行認證邏輯
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
        System.out.println("執行認證邏輯");
        return null;
    }

}

2. 資源權限的攔截

Shiro 自帶很多的攔截器,比如常用的過濾器

annon 無需登錄,可以訪問
authc:必須認證纔可以訪問
user:如果使用remberme的功能 可以直接訪問
perms:該資源必須授權
role:該資源必須得到角色權限纔可以訪問

需求1:當我訪問add或者update的時候,需要進行登錄

@Configuration
public class ShiroConfig {

    /**
     * 創建ShiroFilterFactoryBean
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        HashMap<String, String> filterMap = new HashMap<>();
        filterMap.put("/addOrder","authc");
        filterMap.put("/updateOrder","authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        return shiroFilterFactoryBean;
    }

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

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

實現後大致效果如下
在這裏插入圖片描述

3. 自定義跳轉頁面

 /**
     * 創建ShiroFilterFactoryBean
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        /**
         * 常用的過濾器:annon 無需登錄,可以訪問
         *             authc:必須認證纔可以訪問
         *             user:如果使用remberme的功能 可以直接訪問
         *             perms:該資源必須授權
         *             role:該資源必須得到角色權限纔可以訪問
         */
        HashMap<String, String> filterMap = new HashMap<>();
        filterMap.put("/addOrder","authc");
        filterMap.put("/updateOrder","authc");
        shiroFilterFactoryBean.setLoginUrl("/login");    -----> 跳轉頁面
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);

        return shiroFilterFactoryBean;
    }

4. 用戶登錄的驗證

前臺

<body>
<h3 th:text="${msg}" style="color: red"></h3>
	<h1>權限控制登陸系統</h1>
	<form action="/tologin" method="get">
		<!--username,username 不更改名字-->
		<span>用戶名稱</span><input type="text" name="username" /> <br>
		<span>用戶密碼</span><input type="password" name="password" /> <br>
		<input type="submit" value="登陸"> 
	</form>
</body>
</html>

後臺controller

 // 自定義登陸頁面
    @GetMapping("/tologin")
    public String login(String username, String password, Model model) {
        //獲取subject
        Subject subject = SecurityUtils.getSubject();
        //封裝用戶數據
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        //執行登錄方法
        try {
            subject.login(token);
            return "main";
        } catch (UnknownAccountException e) {
            model.addAttribute("msg", "用戶名不存在");
            return "login";
        } catch (IncorrectCredentialsException e) {
            model.addAttribute("msg", "密碼錯誤");
            return "login";
        }
    }

後臺認證邏輯

  /**
     * 執行認證邏輯
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("執行認證邏輯");
        String name = "admin";
        String password = "123";
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        if (!token.getUsername().equals(name)){
            //用戶名不存在
            return null;  //底層會拋出用戶名不存在異常
        }

        if (!token.getUsername().equals(name)){
            //用戶名不存在
            return null;  //底層會拋出用戶名不存在異常
        }

        //判斷密碼
        return new SimpleAuthenticationInfo("",password,"");  //判斷密碼 我們交給框架去執行
    }

對tologin頁面不進行攔截.放行他

 @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        /**
         * 常用的過濾器:anon 無需登錄,可以訪問
         *             authc:必須認證纔可以訪問
         *             user:如果使用remberme的功能 可以直接訪問
         *             perms:該資源必須授權
         *             role:該資源必須得到角色權限纔可以訪問
         */
        HashMap<String, String> filterMap = new HashMap<>();
        filterMap.put("/addOrder","authc");
        filterMap.put("/updateOrder","authc");
        filterMap.put("/tologin","anon"); //-->>放行
        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);

        return shiroFilterFactoryBean;
    }

當代用 Subject subject = SecurityUtils.getSubject();時,其實走的邏輯的就是AuthenticationInfo 的設定的邏輯
在這裏插入圖片描述

5. 整合mybaties用戶登錄的驗證

1.添加依賴

<!-- 導入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>

2. 配置application.properties

spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

mybatis.type-aliases-package=com.itheima.domain

4.編寫實體類

package com.itheima.domain;

public class User {
	private Integer id;
	private String name;
	private String password;
	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.編寫mapper

package com.itheima.mapper;

import com.itheima.domain.User;

public interface UserMapper {

	public User findByName(String name);
}

4.編寫實現類

package com.itheima.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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);
	}

	
}


5.編寫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>
</mapper>

6.啓動類

package com.itheima;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * SpringBoot啓動類
 * @author lenovo
 *
 */
@SpringBootApplication
@MapperScan("com.itheima.mapper")
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

實現的效果大致如下
在這裏插入圖片描述

6. 使用shiro攔截器實現授權頁面攔截

改動如下

@Configuration
public class ShiroConfig {

    /**
     * 創建ShiroFilterFactoryBean
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        /**
         * 常用的過濾器:annon 無需登錄,可以訪問
         *             authc:必須認證纔可以訪問
         *             user:如果使用remberme的功能 可以直接訪問
         *             perms:該資源必須授權
         *             role:該資源必須得到角色權限纔可以訪問
         */
        HashMap<String, String> filterMap = new HashMap<>();
        filterMap.put("/addOrder","authc");
        filterMap.put("/updateOrder","authc");
        filterMap.put("/tologin","anon");
        filterMap.put("/deleteOrder","perms[user:add]");  //沒有權限直接401,光登錄成功還不行
        filterMap.put("/","authc");
        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setUnauthorizedUrl("/noauth");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        return shiroFilterFactoryBean;
    }

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

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

在這裏插入圖片描述

7.給用戶授予權限

public class UserRealm extends AuthorizingRealm {
    @Autowired
    private UserserServiceImpl UserserServiceImpl;

    /**
     * 執行授權邏輯
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
        System.out.println("執行授權邏輯");
        //給資源進行授權
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //添加資源的授權的字符串
        info.addStringPermission("user:add");  // 這裏一定要和前面的config 一致
        return info;
    }

    /**
     * 執行認證邏輯
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        User user = UserserServiceImpl.findByName(token.getUsername());
        if(user==null){
            //用戶名不存在
            return null;//shiro底層會拋出UnKnowAccountException
        }
        //2.判斷密碼
        return new SimpleAuthenticationInfo("",user.getPassword(),"");

    }

}

8.Mybaties和授權的結合

對所有的增 改 刪 增加了權限

@Configuration
public class ShiroConfig {

    /**
     * 創建ShiroFilterFactoryBean
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        /**
         * 常用的過濾器:annon 無需登錄,可以訪問
         *             authc:必須認證纔可以訪問
         *             user:如果使用remberme的功能 可以直接訪問
         *             perms:該資源必須授權
         *             role:該資源必須得到角色權限纔可以訪問
         */
        HashMap<String, String> filterMap = new HashMap<>();
        filterMap.put("/addOrder","authc");
        filterMap.put("/updateOrder","authc");
        filterMap.put("/deleteOrder","authc");
        filterMap.put("/tologin","anon");
        filterMap.put("/deleteOrder","perms[user:delete]");  //沒有權限直接401,光登錄成功還不行
        filterMap.put("/updateOrder","perms[user:update]");  //沒有權限直接401,光登錄成功還不行
        filterMap.put("/addOrder","perms[user:add]");  //沒有權限直接401,光登錄成功還不行
        filterMap.put("/","authc");
        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setUnauthorizedUrl("/noauth");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        return shiroFilterFactoryBean;
    }

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

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

結合數據庫添加權限的判斷

public class UserRealm extends AuthorizingRealm {
    @Autowired
    private UserserServiceImpl UserserServiceImpl;

    /**
     * 執行授權邏輯
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
        System.out.println("執行授權邏輯");
        //給資源進行授權
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //添加資源的授權的字符串
        //獲取當前登錄的用戶
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipal();  -------> 注意這裏獲取的user其實也就
        User byId = UserserServiceImpl.getById(user.getId());
        info.addStringPermission(byId.getPerms());
        return info;
    }

    /**
     * 執行認證邏輯
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        User user = UserserServiceImpl.findByName(token.getUsername());
        if(user==null){
            //用戶名不存在
            return null;//shiro底層會拋出UnKnowAccountException
        }
        //2.判斷密碼![在這裏插入圖片描述](https://img-blog.csdnimg.cn/20191229162939534.gif)
        return new SimpleAuthenticationInfo(user,user.getPassword(),"");  ----> user爲了subject.getPrincipal();獲取

    }

}

在這裏插入圖片描述

9. Thymeleaf 整合shiro

1. 添加依賴

    <!-- thymel對shiro的擴展座標 -->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

2. ShiroConfig 增加配置類


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

3.整改前臺,當含有某個權限的時候,顯示該功能欄

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:shiro="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    <title>Insert title here</title>
</head>
<body>
<h1>訂單系統</h1>
<br>
<div shiro:hasPermission="user:select">
    <a href="showOrder">查詢訂單</a>
</div>
<br>
<div shiro:hasPermission="user:add">
    <a href="addOrder">添加訂單</a>
    <br>
</div>
<div shiro:hasPermission="user:delete">
<a href="deleteOrder">刪除訂單</a>
<br></div>

<div shiro:hasPermission="user:update">
    <a href="updateOrder">修改訂單</a>
</div>
</form>
</body>
</html>

最後看下實際效果圖吧,(展示的時候有點小翻車…)
在這裏插入圖片描述

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