SpringBoot 整合 Shiro 快速入门教程

0. Gitee项目地址

XINGLIBAO / springboot-shiro

1. Shiro简介

Apache Shiro是一款主流的 Java 安全框架,不依赖任何容器,可以运行在 Java SE 和 Java EE 项目中,它的主要作用是对访问系统的用户进行身份认证、授权、会话管理、加密等操作。

Apache Shiro | Simple. Java. Security.

2. Shiro核心组件

  • UsernamePasswordToken:

    Shiro 用来封装用户登录信息,使用用户的登录信息来创建令牌 Token
    在这里插入图片描述

  • SecurityManager:

    Shiro 的核心部分,负责安全认证和授权

  • Subject:

    Shiro 的一个抽象概念,包含了用户信息

  • Realm:

    开发者自定义的模块,根据项目的需求,验证和授权的逻辑全部写在 Realm 中
    在这里插入图片描述

  • AuthenticationInfo:

    用户的角色信息集合,认证时使用

  • AuthorzationInfo:

    角色的权限信息集合,授权时使用

  • DefaultWebSecurityManager:

    安全管理器,开发者自定义的 Realm 需要注入到 DefaultWebSecurityManager 进行管理才能生效

  • ShiroFilterFactoryBean:

    过滤器工厂,Shiro 的基本运行机制是开发者定制规则,Shiro 去执行,具体的执行操作就是由 ShiroFilterFactoryBean 创建的一个个 Filter 对象来完成

3. Shiro运行机制

在这里插入图片描述

4. SpringBoot 整合 Shiro

(1) 创建 SpringBoot 应用,集成 Shiro 等相关组件

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.5.3</version>
</dependency>

(2) 自定义 Shiro 过滤器

package com.lichun.realm;

import com.lichun.entity.Account;
import com.lichun.service.AccountService;
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.HashSet;
import java.util.Set;

/**
 * @Author: xinglibao
 * @Date: 2021/10/19 8:29
 * 自定义Shiro过滤器
 */
public class AccountRealm extends AuthorizingRealm {

    @Autowired
    private AccountService accountService;

    /**
     * 授权
     * @param principalCollection 角色的权限信息集合,授权时使用
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // 获取当前用户的登录信息
        Subject subject = SecurityUtils.getSubject();
        Account account = (Account) subject.getPrincipal();

        // 设置角色
        Set<String> roles = new HashSet<>();
        roles.add(account.getRole());
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);

        // 设置权限
        info.addStringPermission(account.getPerms());
        return info;
    }

    /**
     * 认证
     * @param authenticationToken 用户的角色信息集合,认证时使用
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        /**
         * public class UsernamePasswordToken implements HostAuthenticationToken, RememberMeAuthenticationToken
         * public interface HostAuthenticationToken extends AuthenticationToken
         */
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        Account account = accountService.findByUsername(token.getUsername());
        if (account != null) {
            /**
             * public SimpleAuthenticationInfo(Object principal, Object credentials, String realmName)
             *
             * public abstract class AuthorizingRealm extends AuthenticatingRealm
             *         implements Authorizer, Initializable, PermissionResolverAware, RolePermissionResolverAware
             * public abstract class AuthenticatingRealm extends CachingRealm implements Initializable
             * public abstract class CachingRealm implements Realm, Nameable, CacheManagerAware, LogoutAware
             *
             * getName()方法在CachingRealm中
             * 而AuthenticatingRealm继承了CachingRealm,AuthorizingRealm继承了AuthenticatingRealm,AuthorizingRealm extends AuthenticatingRealm
             * 最终AccountRealm继承了AuthorizingRealm
             */
            return new SimpleAuthenticationInfo(account, account.getPassword(), getName());
        }
        return null;
    }
}

(3) 配置类

package com.lichun.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.lichun.realm.AccountRealm;
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.Hashtable;
import java.util.Map;

/**
 * @Author: xinglibao
 * @Date: 2021/10/19 8:28
 */
@Configuration
public class ShiroConfig {

    /**
     * dialect 方言
     * @return
     */
    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean
            (@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        // 编写认证和授权规则
        Map<String, String> map = new Hashtable<>();
        /**
         * 必须登录才能访问main.html
         * authc: 必须认证
         */
        map.put("/main", "authc");
        /**
         * perms: 必须拥有某个权限才能访问
         * 当前用户必须拥有manage授权才能访问manage.html
         */
        map.put("/manage","perms[manage]");
        /**
         * role: 必须拥有某个角色才能访问
         * 当前用户必须拥有administrator角色才能访问administrator.html
         */
        map.put("/administrator","roles[administrator]");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);

        // 设置登录页面
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 设置未授权页面
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauth");

        return shiroFilterFactoryBean;
    }

    @Bean
    public DefaultWebSecurityManager securityManager
            (@Qualifier("accountRealm") AccountRealm accountRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(accountRealm);
        return securityManager;
    }

    @Bean
    public AccountRealm accountRealm() {
        return new AccountRealm();
    }
}

(4) 编写认证和授权规则

认证过滤器

  • anon:无需认证
  • authc:必须认证
  • authcBasic:需要通过 HTTPBasic 认证
  • user:不一定通过认证,只要曾经被 Shiro 记录即可,比如:记住我。

授权过滤器

  • perms:必须拥有某个权限才能访问
  • role:必须拥有某个角色才能访问
  • port:请求的端口必须是指定值才可以
  • rest:请求必须基于 RESTful,POST、PUT、GET、DELETE
  • ssl:必须是安全的 URL 请求,协议 HTTPS

5. Shiro 整合 Tymeleaf

(1) 引入依赖

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

(2 )配置类添加 ShiroDialect

@Bean
public ShiroDialect shiroDialect() {
    return new ShiroDialect();
}

(3) index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
    <meta charset="UTF-8">
    <title>index</title>
    <!--不加下面这一行会报错,但是没影响-->
    <link rel="shortcut icon" href="#"/>
    <!--这个页面的主要功能就是如果你已经登陆过了,来到此页面会显示欢迎回来
    并且这个页面会根据你是否有相应的角色、权限给你显示菜单-->
</head>
<body>

    <h1>index</h1>


    <div th:if="${session.account != null}">
        <span th:text="${session.account.username} + '欢迎回来'"></span>
        <a href="/logout">退出</a>
    </div>


    <a href="/main">main</a><br/>


    <div shiro:hasPermission="manage">
        <a href="/manage">manage</a><br/>
    </div>
    <div shiro:hasRole="administrator">
        <a href="/administrator">administrator</a>
    </div>

</body>
</html>

6. account表

在这里插入图片描述

7. B站学习地址

【硬核干货】2小时学会Spring Boot整合Shiro

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

枯木何日可逢春

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值