Spring整合Shiro,SpringBoot整合Shiro

Shiro

Shiro的三大功能

Shiro有三大核心组件,即SubjectSecurityManagerRealm

  • Subject : 为认证主体。应用代码直接交互的对象是Subject,Subject代表了当前的用户。包含PrincipalsCredentials两个信息。
  • SecurityManager :为安全管理员。是Shiro架构的核心。与Subject的所有交互都会委托给SecurityManager, Subject相当于是一个门面,而SecurityManager才是真正的执行者。它负责与Shiro 的其他组件进行交互。
  • Realm :是一个域。充当了Shiro与应用安全数据间的"桥梁"。Shiro从Realm中获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm中获取相应的用户进行比较,来确定用户的身份是否合法;也需要从Realm得到用户相应的角色、权限,进行验证用户的操作是否能过进行,可以把Realm看成DataSource,即安全数据源。
  • Authentication: 身份认证、登录,验证用户是不是拥有相应的身份;
  • Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限,即判断用户能否进行什么操作,如:验证某个用户是否拥有某个角色,或者细粒度的验证某个用户对某个资源是否具有某个权限!
  • Session Manager: 会话管理,即用户登录后就是第-次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通的JavaSE环境,也可以是Web环境;
  • Cryptography: 加密,保护数据的安全性,如密码加密存储到数据库中,而不是明文存储;
  • Web Suppor: Web支持,可以非常容易的集成到Web环境;
  • Caching: 缓存,比如用户登录后,其用户信息,拥有的角色、权限不必每次去查,这样可以提高效率
  • Concurrency: Shiro支持多线程应用的并发验证,即,如在一个线程中开启另一个线程,能把权限自动的传播过去
  • Testing:提供测试支持;
  • RunAs:允许一个用户假装为另-一个用户(如果他们允许)的身份进行访问;
  • Remember Me:记住我,这个是非常常见的功能,即一-次登录后, 下次再来的话不用登录了

Shiro架构(外部)

从外部来看Shiro,即从应用程序角度来观察如何使用shiro完成工作: Subject 用户,SecurityManager管理所有用户 Realm连接数据

  • subject : 应用代码直接交互的对象是Subject, 也就是说Shiro的对外API核心就是Subject, Subject代表了当前的用户,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等,与Subject的所有交互都会委托给SecurityManager; Subject其实是一一个门面, SecurityManageer 才是实际的执行者。
  • SecurityManager : 安全管理器,即所有与安全有关的操作都会与SercurityManager交互, 并且它管理着所有的Subject,可以看出它是Shiro的核心,它负责与Shiro的其他组件进行交互,它相当于SpringMVC的DispatcherServlet的角色
  • Realm : Shiro从Realm获取安全数据 (如用户,角色,权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较,来确定用户的身份是否合法;也需要从Realm得到用户相应的角色、权限,进行验证用户的操作是否能够进行,可以把Realm看DataSource;

Shiro架构(内部)

  • Subject: 任何可以与应用交互的用户;
  • Security Manager :相当于SpringMVC中的DispatcherSerlet; 是Shiro的心脏, 所有具体的交互都通过Security Manager进行控制,它管理者所有的Subject, 且负责进行认证,授权,会话,及缓存的管理。
  • Authenticator :负责Subject认证, 是-一个扩展点,可以自定义实现;可以使用认证策略(Authentication Strategy),即什么情况下算用户认证通过了;
  • Authorizer:授权器,即访问控制器,用来决定主体是否有权限进行相应的操作;即控制着用户能访问应用中 的那些功能;
  • Realm: 可以有-一个或者多个的realm, 可以认为是安全实体数据源,即用于获取安全实体的,可以用JDBC实现,也可以是内存实现等等,由用户提供;所以- -般在应用中都需要实现自己的realm
  • SessionManager:管理Session生 命周期的组件,而Shiro并不仅仅可以用在Web环境,也可以用在普通的JavaSE环境中
  • CacheManager: 缓存控制器,来管理如用户,角色,权限等缓存的;因为这些数据基本上很少改变,放到缓存中后可以提高访问的性能;
  • Cryptography:密码模块,Shiro 提高了一些常见的加密组件用于密码加密, 解密等

shiro认证过程

shiro授权过程

![BXL6]K(]B%(WYJNOO2P)IY.png

shiro使用

SaaSExport练习项目使用(ssm)

pom.xml依赖

xml 复制代码
<!--Shiro和Spring整合-->
<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-spring</artifactId>
  <version>1.3.2</version>
</dependency>
<!--Shiro核心包-->
<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-core</artifactId>
  <version>1.3.2</version>
</dependency>

web.xml

xml 复制代码
<!--服务器启动时加载Spring配置文件-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
      classpath:spring.xml
      classpath:shiro.xml
    </param-value>
  </context-param>
  
  <!--Shiro核心过滤器-->
  <filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

shiro.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
​
    <!--id=shiroFilter不能写错,大小写敏感,这个id的值与filter的名字相同-->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="defaultWebSecurityManager"/>
        <!--**表示当前路径下所有资源,包括一级目录,二级目录,等等-->
        <!--anon放在最前面,authc放在最后面-->
        <property name="filterChainDefinitions">
            <value>
                /css/** = anon
                /img/** = anon
                /make/** = anon
                /plugins/** = anon
                /login.do = anon
​
                /system/dept/list.do = perms["部门管理"]
                /system/user/list.do = perms["用户管理"]
                /system/company/list.do = perms["企业管理"]
                /system/module/list.do = perms["模块管理"]
                /system/role/list.do = perms["角色管理"]
                /system/syslog/list.do = perms["日记管理"]
​
                /** = authc
            </value>
        </property>
        <property name="unauthorizedUrl" value="/unauthorized.jsp"/>
    </bean>
​
​
    <bean id="defaultWebSecurityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="authReaml"/>
    </bean>
​
​
    <bean id="authReaml" class="com.it.shiro.AuthReaml">
<!--        &lt;!&ndash;将123456转成MD5格式的密码,然后再和数据库中的MD5密码进行比较&ndash;&gt;-->
<!--        &lt;!&ndash;所以在企业开发中,配置方式很常用,可拔插&ndash;&gt;-->
<!--        <property name="credentialsMatcher" ref="hashedCredentialsMatcher"/>-->
    </bean>
​
    <!--我们使用MD5加密器-->
<!--    <bean id="hashedCredentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">-->
<!--        <property name="hashAlgorithmName" value="MD5"/>-->
<!--    </bean>-->
​
​
</beans>
权限参数表

实现类AuthReaml

这个练习项目的权限是基于RBAC模型,用户表、角色表、模块表以及两个中间表,通过用户与角色的中间表获取用户对应的角色,然后通过角色与模块的中间表获取对应的权限,这也是典型的反三范式数据表设计(虽然我已经忘记三范式是哪三个了,不会还有人严格遵守三范式去设计数据表了吧?)

java 复制代码
package com.it.shiro;
​
import com.it.model.module.Module;
import com.it.model.user.User;
import com.it.service.module.ModuleService;
import com.it.service.user.UserService;
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.List;
​
/**
 * 自定义Shiro认证和权授的业务逻辑
 */
public class AuthReaml extends AuthorizingRealm {
    @Autowired
    private UserService userService;
    @Autowired
    private ModuleService moduleService;
    /**
     * 认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("认证");
        //1. 将AuthenticationToken接口强转成UsernamePasswordToken实现类并从中获取用户输入的用户名(邮箱)和密码
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username = token.getUsername();
        String password = new String(token.getPassword());//char[]->java.lang.String
        //2. 根据用户名(邮箱)去数据库中查询用户是否存在,userDB中有密码
        User userDB = userService.findByEmail(username);
        //3. 如果用户不存在,就返回null
        if(userDB == null){
            System.out.println("用户不存在");
            return null;
        }
        System.out.println("uid   "+userDB.getUserId());
        System.out.println("password   "+userDB.getPassword());
​
        //4. 如果用户存在,就返回AuthenticationInfo接口的SimpleAuthenticationInfo实现类对象,该对象中封装三个信息:
        ////a)认证后的userDB对象
        ////b)认证后的userDB对象封装的数据库密码
        ////c)Realm的别名,可以为""
        AuthenticationInfo info = new SimpleAuthenticationInfo(userDB,userDB.getPassword(),"");
        //Shiro会在后台对userDB.getPassword()数据库密码和password用户填写的密码在内存中对比
        return info;
    }
​
    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("授权");
        //1. 使用SecurityUtils获取Subject对象
        Subject subject = SecurityUtils.getSubject();
        //2. 使用Subject对象获取User对象
        User loginUser = (User) subject.getPrincipal();
        //3. 根据用户ID查询该用户可以访问的模块,这里的moduleList集合中Module只有模块名name属性
        List<Module> moduleList = moduleService.findModuleByUid(loginUser.getUserId());
//        List<Module> moduleList = moduleService.findByUserId(loginUser.getId());
        //4. 遍历模块集合,将每一个模块的编号或名称封装到
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        for (Module module : moduleList) {
            //info.addStringPermission("部门管理");
            info.addStringPermission(module.getName());
        }
        //SimpleAuthorizationInfo对象中,以便Shiro内容进行授权控制
        //5. 返回SimpleAuthorizationInfo对象
        return info;
    }
​
​
}

调用方法

scss 复制代码
//1.使用SecurityUtils获取subject对象
Subject subject = SecurityUtils.getSubject();
//2.使用AuthenticationToken接口的UsernamePasswordToken实现类封装用户输入的用户名(邮箱)和密码信息
AuthenticationToken token = new UsernamePasswordToken(username,password);
//3.调用subject的login()进行认证,底层调用AuthRealm.doGetAuthenticationInfo()认证方法
subject.login(token);
//4. 调用subject的getPrincipal()获取认证后的用户,这个userDB就是数据库的密码
User userDB = (User) subject.getPrincipal();
//5. 将用户放入session中
request.getSession().setAttribute("loginUser",userDB);

SpringBoot使用(网上摘抄的)

pom.xml

org.apache.shiro shiro-spring 1.4.1

config配置

新建一个config包,并创建ShiroConfig和UserRealm

typescript 复制代码
@Controller
public class ShiroConfig {
    //三大核心要素:
​
    //ShiroFilterFactoryBean
    //第三步:
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);
        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();
    }
}
scala 复制代码
public class UserRealm extends AuthorizingRealm {
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了=》授权doGetAuthorizationInfo");
        return null;
    }
​
    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行了=》认证doGetAuthenticationInfo");
        return null;
    }
}

相关资料

SpringBoot整合shiro

juejin.cn/post/699166...

zhuanlan.zhihu.com/p/54176956

相关推荐
威哥爱编程4 天前
适合才最美:Shiro安全框架使用心得
java·shiro·javaee
菠萝咕噜肉i4 天前
SpringBoot+Shiro权限管理
java·spring boot·后端·shiro
昵称为空C1 个月前
SpringBoot集成Shiro权限+Jwt认证
spring boot·shiro
杨同学technotes3 个月前
【译】Apache Shiro介绍
后端·安全·shiro
月色无痕4 个月前
升级springboot3.2集成shiro的问题
shiro·springboot3.x
一只特立独行的猪6114 个月前
Shiro框架2
安全·shiro
shyの同学5 个月前
分布式Shiro,SpringBoot项目Shiro整合Redis
spring boot·redis·分布式·shiro
AskHarries5 个月前
Spring Boot集成shiro之使用redis缓存demo
java·spring boot·后端·shiro
AskHarries6 个月前
Spring Boot集成Shiro快速入门Demo
spring boot·后端·shiro
餘yuqn7 个月前
springboot 整合 shiro 框架自定义登录验证和权限管理
spring boot·后端·shiro