springboot整合shiro

本文详细介绍了SpringBoot如何与Shiro进行整合,重点讲解了Shiro的三大核心组件——Subject、SecurityManager和Realm,以及它们在权限管理和认证过程中的作用。同时,概述了Shiro的功能,包括身份认证、授权、会话管理、加密和Web支持等。文中还给出了Shiro整合SpringBoot的具体步骤,包括创建实体、数据操作、配置核心Realm、Shiro配置以及异常处理,并提供了测试示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. Shiro三个核心组件
    1.1 Subject
      Subject:即“当前操作用发户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。但考虑到大多数目的和用途,你可以把它认为是Shiro的“用户”概念。Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
    1.2 SecurityManager
      SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
    1.3 Realm
      Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
      从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
      Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。

2.Shiro相关类介绍

  1. Authentication:身份认证/登录(账号密码验证)。
  2. Authorization:授权,即角色或者权限验证。
  3. Session Manager:会话管理,用户登录后的session相关管理。
  4. Cryptography:加密,密码加密等。
  5. Web Support:Web支持,集成Web环境。
  6. Caching:缓存,用户信息、角色、权限等缓存到如redis等缓存中。
  7. Concurrency:多线程并发验证,在一个线程中开启另一个线程,可以把权限自动传播过去。
  8. Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问。
  9. Remember Me:记住我,登录后,下次再来的话不用登录了。

3.shiro整合springboot代码

3.1先创建我们的三个实体
userInfo用户实体

@ApiModel(value="UserInfo对象", description="")
@Data
public class UserInfo implements Serializable {

private static final long serialVersionUID=1L;

    public UserInfo(Integer id, String userName, String password, List<RoleInfo> roleInfoList) {
        this.id = id;
        this.userName = userName;
        this.password = password;
        this.roleInfoList = roleInfoList;
    }

    public UserInfo() {
    }

    private Integer id;

    @ApiModelProperty(value = "用户名")
    private String userName;

    @ApiModelProperty(value = "密码")
    private String password;

    @ApiModelProperty(value = "角色集合")
    private List<RoleInfo> roleInfoList;

}
@ApiModel(value="RoleInfo对象", description="")
@Data
public class RoleInfo implements Serializable {

private static final long serialVersionUID=1L;

    public RoleInfo(Integer id, String roleName, List<AuthorityInfo> authorityInfoList) {
        this.id = id;
        this.roleName = roleName;
        this.authorityInfoList = authorityInfoList;
    }

    public RoleInfo() {
    }

    private Integer id;

    @ApiModelProperty(value = "角色名")
    private String roleName;

    @ApiModelProperty(value = "角色所拥有的权限")
    private List<AuthorityInfo> authorityInfoList;
}
@ApiModel(value="AuthorityInfo对象", description="")
@Data
public class AuthorityInfo implements Serializable {

private static final long serialVersionUID=1L;

    public AuthorityInfo(Integer id, String authorityName) {
        this.id = id;
        this.authorityName = authorityName;
    }

    public AuthorityInfo() {
    }

    private Integer id;

    @ApiModelProperty(value = "权限名")
    private String authorityName;
}

3.2数据操作
由于没有连接数据库,
设置了两个用户(admin,zhangsan)
两个权限(add,query)
两个角色(admin,ordinary)

private UserInfo simulationGetInfo(String userName) {
    // 设置两个权限 一个add 一个query
    AuthorityInfo authorityInfoAdd = new AuthorityInfo(1,"add");
    AuthorityInfo authorityInfoQuery = new AuthorityInfo(2,"query");
    // 查询权限集合
    List<AuthorityInfo> queryList = Lists.newArrayList();
    queryList.add(authorityInfoQuery);
    // 所有权限集合
    List<AuthorityInfo> allList = Lists.newArrayList();
    allList.add(authorityInfoAdd);
    allList.add(authorityInfoQuery);

    // 设置两个角色 一个管理员 一个普通用户
    RoleInfo adminRole = new RoleInfo(1,"admin",allList);
    RoleInfo ordinaryRole = new RoleInfo(2,"ordinary",queryList);

    // 设置两个用户
    UserInfo adminUser = new UserInfo(1,"admin","123456", Collections.singletonList(adminRole));
    UserInfo zhangsanUser = new UserInfo(2,"zhangsan","123456",Collections.singletonList(ordinaryRole));

    Map<String,UserInfo> map = Maps.newHashMap();
    map.put(adminUser.getUserName(),adminUser);
    map.put(zhangsanUser.getUserName(),zhangsanUser);

    return map.get(userName);
}

配置我们的核心Realm

public class CustomerRealm extends AuthorizingRealm {

    @Autowired
    private ISysLoginService iSysLoginService;

    /**
     * 授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // 获得用户登录名
        UserInfo userInfo = iSysLoginService.getUserInfo(principalCollection.getPrimaryPrincipal().toString());
        //添加角色和权限
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        for (RoleInfo roleInfo : userInfo.getRoleInfoList()) {
            simpleAuthorizationInfo.addRole(roleInfo.getRoleName());
            for (AuthorityInfo authorityInfo : roleInfo.getAuthorityInfoList()) {
                simpleAuthorizationInfo.addStringPermission(authorityInfo.getAuthorityName());
            }
        }
        return simpleAuthorizationInfo;
    }

    /**
     * 认证 用户登录
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 加这一步的目的是在请求的时候会先进认证,然后在到请求
        if (authenticationToken.getPrincipal() == null) {
            return null;
        }
        //获取用户信息
        UserInfo userInfo = iSysLoginService.getUserInfo(authenticationToken.getPrincipal().toString());
        if (userInfo == null) {
            //这里返回后会报出对应异常
            return null;
        } else {
            //这里验证authenticationToken和simpleAuthenticationInfo的信息
            return new SimpleAuthenticationInfo(userInfo.getUserName(), userInfo.getPassword(), getName());
        }
    }
}

shiro配置

@Configuration
public class ShiroConfig {

    /**
     * 该配置可解决shiro注解无法被映射问题
     *
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    /**
     * 将自己的验证方式加入容器
     *
     * @param
     * @return: com.dpx.shiro.handle.CustomerRealm
     * @author:
     * @date: 2020/4/16
     */
    @Bean
    public CustomerRealm myShiroRealm() {
        CustomerRealm customRealm = new CustomerRealm();
        return customRealm;
    }

    /**
     * 权限管理,核心,配置主要是Realm的管理认证
     *
     * @param
     * @return: org.apache.shiro.mgt.SecurityManager
     * @author:
     * @date: 2020/4/16
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        return securityManager;
    }

    /**
     * Filter工厂,设置对应的过滤条件和跳转条件
     *
     * @param securityManager
     * @return: org.apache.shiro.spring.web.ShiroFilterFactoryBean
     * @author:
     * @date: 2020/4/16
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String, String> map = new HashMap<>();
        /**
         * Shiro内置过滤器,可以实现权限相关的拦截器
         * anon: 无需认证(登录)可以访问
         * authc: 必须认证才可以访问
         * user: 如果使用rememberMe的功能可以直接访问
         * perms: 该资源必须得到资源权限才可以访问
         * role: 该资源必须得到角色权限才可以访问
         */
        map.put("/login", "anon");
        map.put("/add", "authc");
        //登录
        shiroFilterFactoryBean.setLoginUrl("/login");
        //错误页面,认证不通过跳转
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }

    /**
     * 注解访问授权动态拦截,不然不会执行doGetAuthenticationInfo
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}

我们的两个入口

@RestController
public class SysLoginController {

    @RequestMapping(value = "/login")
    public String login(@RequestBody UserInfo userInfo) {
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken passwordToken = new UsernamePasswordToken(userInfo.getUserName(), userInfo.getPassword());
        try {
            subject.login(passwordToken);
        } catch (AuthenticationException e) {
            return "账号密码错误";
        } catch (AuthorizationException e) {
            return "没有权限";
        }
        return "登录成功";
    }

    @RequiresRoles("admin")
    @RequiresPermissions("add")
    @RequestMapping(value = "/add")
    public String add() {
        return "添加信息";
    }
}

简单配置一个全局异常处理

@ControllerAdvice
public class ShiroException {

    @ExceptionHandler
    @ResponseBody
    public String noAuthorityHandler(AuthorizationException e){
        return "没有该权限";
    }
}

4.测试一下结果
用我们的admin账号登录
在这里插入图片描述
再来请求add接口在这里插入图片描述
用zhangsan普通账号登录
在这里插入图片描述
接下来访问add接口
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值