SpringBoot整合Shiro安全框架(一)

综述:

   Shiro框架是Apache旗下的一个开源项目,它是轻量级安全框架,非常简便易用,同Spring旗下的Security安全框架相比较,它更加简便,易用和灵活,没有Security复杂。Shiro包括:认证、授权、加密和会话管理等功能。

主要功能:

   1、验证用户身份
   2、用户授权,权限访问
   3、支持单点登录(SSO)功能
   4、提供记住我(Remember me)功能等

框架体系:

   框架体系大概分为如下几种:
在这里插入图片描述

1、Authentication(认证):用户识别(你是谁)
2、AUthorization(授权):访问控制(你能干什么),也就是对访问权限的控制
3、Session Management(会话管理):对用户的会话管理
4、Cryptography(加密):对数据源的加密,防止进行窃取

主要流程:

   在概念层,Shiro架构包含三个主要的理念:Subject、SecurityManager和Realm。下面将展示这三个组件如何相互作用。Shiro的执行流程图如下所示:
在这里插入图片描述
三个主要理念:
   Subject:代表当前用户,Subject 可以是一个人,也可以是第三方服务、守护进程帐户、时钟守护任务或者其它当前和软件交互的任何事件。
   SecurityManager:管理所有的Subject,SecurityManager是Shiro框架的核心,配合内部安全组件共同组成安全伞。
   Realm:是进行权限信息的验证,这个需要我们自己去进行实现。它的本质就是一个特定的安全的Dao层:它封装了与数据源连接的细节,得到Shiro所需的相关数据。
在我们实现Realm的时候,需要继承AuthorizingRealm类,重写AuthorizationInfo(授权方法)和AuthenticationInfo认证方法。

Spring Boot整合Shiro实例:

1、导入Shiro整合SpringBoot的依赖

   代码如下所示:

<!--spring Boot和shiro的整合-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.1</version>
        </dependency>

2、创建Shiro配置文件并且创建自定义Realm进行验证和授权

   Realm的文件如下所示:

package com.ygl.config;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

/**
 * @author ygl
 * @description
 * @date 2020/11/6 10:41
 */
//自定义的 UserRealm
public class UserRealm extends AuthorizingRealm {
    
    
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    
    
        System.out.println("执行了授权功能=》doGetAuthorizationInfo!");
        return null;
    }
    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    
    
        System.out.println("执行了认证功能=》doGetAuthorizationInfo!");
        //用户名  密码   数据库中取
        String name = "root";
        String password = "123456";
        UsernamePasswordToken userToken = (UsernamePasswordToken)token;
        if (!userToken.getUsername().equals(name)){
    
    //token中获取的name和数据中的name进行比较,如果不对返回null,shiro自动给我们进行捕获异常为用户名错误异常
            return null;
        }
        //密码认证   shiro来进行操作,防止获取到密码
        return new SimpleAuthenticationInfo("",password,"");

    }
}

   自定义Realm继承AuthorizingRealm类,重写doGetAuthorizationInfo(授权)和doGetAuthenticationInfo(验证)方法。这里未连接数据库,直接将用户和密码写死了,然后进行用户名验证和密码验证,密码验证直接交由Shiro进行验证,防止窃取密码。具体功能在注释中表明的有,请仔细看注释。
   ShiroConfig配置如下所示:

package com.ygl.config;

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.LinkedHashMap;
import java.util.Map;

/**
 * @author ygl
 * @description
 * @date 2020/11/6 10:37
 */
@Configuration
public class ShiroConfig {
    
    

    //ShiroFilterFactoryBean  过滤 (第三步:连接到前端)
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
    
    
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);
        //配置shiro的内置过滤器
        /*
            anon:无需认证就可以访问
            authc:必须认证才可以访问
            user:必须拥有 记住我 功能才能访问
            perms:拥有对某个资源的权限才能访问
            role:拥有某个角色才能访问
         */
        Map<String, String> filterMap = new LinkedHashMap();
        filterMap.put("/toLogin","anon");
//        filterMap.put("/user/add","authc");
//        filterMap.put("/user/update","authc");
        filterMap.put("/user/*","authc");
        bean.setFilterChainDefinitionMap(filterMap);

        //被拦截时 设置登录的请求
        bean.setLoginUrl("/toLogin");

        return bean;
    }

    //DafaultWebSecurityManager 安全对象  (第二步:接管对象)
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
    
    
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联userRealm
        securityManager.setRealm(userRealm);

        return securityManager;

    }


    //创建Realm对象  需要自定义 (第一步:创建对象)
    @Bean
    public UserRealm userRealm(){
    
    
        return new UserRealm();
    }

}

   注解@Configuration一定要记得添加,getShiroFilterFactoryBean方法、getDefaultWebSecurityManager方法和userRealm方法创建时进行一环套一环,一定要从第三个方法到第一个方法去创建。具体创建和理解,麻烦大家进行去看注释,注释里写的比较详细。

   3、Controller层代码如下所示:

package com.ygl.controller;

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.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author ygl
 * @description
 * @date 2020/11/5 20:45
 */
@Controller
public class MyController {
    
    

    @RequestMapping({
    
    "/","/index"})
    public String toIndex(Model model){
    
    
        model.addAttribute("msg","hello,shiro");
        return "index";
    }

    @RequestMapping("/user/add")
    public String add(){
    
    
        return "/user/add";
    }

    @RequestMapping("/user/update")
    public String update(){
    
    
        return "/user/update";
    }

    @RequestMapping("/toLogin")
    public String toLogin(){
    
    
        return "/login";
    }

    @RequestMapping("/login")
    public String login(String username,String password,Model model){
    
    
        //获取当前用户请求
        Subject subject = SecurityUtils.getSubject();
        //封装用户数据
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try {
    
    
            subject.login(token);//执行登陆方法 , 如果没有异常就说明ok‘
            return "index";
        }catch (UnknownAccountException e){
    
    //用户名不存在异常
            model.addAttribute("msg","用户名错误");
            return "login";
        }catch (IncorrectCredentialsException e){
    
    //密码错误
            model.addAttribute("msg","密码错误");
            return "login";
        }

    }
}

尤其注意login方法,此方法中的subject.login(token),自动调用Shiro中的认证方法。我们只需要操作Realm中授权方法进行验证。

下面贴出pom文件和thymeleaf方面的html文件

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 https://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.3.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ygl</groupId>
    <artifactId>shiro-springboot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>shiro-springboot</name>
    <description>Demo project for Spring Boot</description>

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

    <dependencies>

        <!--spring Boot和shiro的整合-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.1</version>
        </dependency>
        <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>
        <!--thymeleaf模板-->
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-java8time</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

index.html代码:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
    <h1>首页</h1>
    <p th:text="${msg}"></p>
    <hr>
    <a th:href="@{/user/add}">添加</a>
    <a th:href="@{/user/update}">更新</a>
</body>
</html>

login.html代码:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
    <p th:text="${msg}" style="color: red"></p>
    <h1>登录页面</h1>
    <hr>
    <form th:action="@{/login}">
        <p>用户名:<input type="text" name="username"></p>
        <p>密码:<input type="text" name="password"></p>
        <p><input type="submit"></p>
    </form>
</body>
</html>

update.html代码:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>更新页面</title>
</head>
<body>
    <h1>update</h1>
</body>
</html>

add.html代码如下所示:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>添加页面</title>
</head>
<body>
    <h1>添加</h1>
</body>
</html>

在这里插入图片描述
大家有那些不懂的,欢迎在下方评论

猜你喜欢

转载自blog.csdn.net/weixin_45150104/article/details/109530549