springboot整合shiro

本文介绍了如何在Spring Boot项目中整合Apache Shiro进行权限管理,包括引入Shiro和Thymeleaf的Shiro标签依赖,自定义Realm进行身份验证和授权,配置Shiro Filter,以及处理权限异常。此外,还展示了使用Shiro注解进行权限控制和Thymeleaf模板引擎中的Shiro标签用法。
摘要由CSDN通过智能技术生成

1. 引入shiro依赖

注意: 我是采用thymeleaf做模板引擎,需要shiro标签做权限判断,所以引用了thymeleaf-extras-shiro依赖

		<!--shiro支持-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.6.0</version>
        </dependency>
        <!--thymeleaf中使用shiro标签做权限判断-->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

2. 自定义realm

在这里插入图片描述
代码如下:

package com.xxqy.shopping.realm;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xxqy.shopping.entity.SysUser;
import com.xxqy.shopping.service.SysUserService;
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 javax.annotation.Resource;
import java.util.HashSet;

/**
 * 自定义Realm
 * @Author yww
 * @CreateTime 2021-06-21
 *
 */
public class CustomRealm extends AuthorizingRealm{

    @Resource
    private SysUserService sysUserService;

    /**
     * 授权方法
     *    操作的时候,判断用户是否具有响应的权限
     *        先认证  --  安全数据
     *        再授权  --  根据安全数据获取用户具有的所有操作权限
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //1.获取已认证的用户数据
        SysUser user = (SysUser) principalCollection.getPrimaryPrincipal();
        //2.根据用户数据获取用户的权限信息(所有角色,所有权限)
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //所有角色
        HashSet<String> roles = new HashSet<>();
        //所有权限
        HashSet<String> perms = new HashSet<>();
        //TODO 查询用户所有角色 设值给roles,所有权限 设值给perms


        info.setStringPermissions(perms);
        info.setRoles(roles);
        return info;
    }

    /**
     * 认证方法
     *    参数: 传递的用户名密码
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //1.获取登录的用户名密码(token)
        UsernamePasswordToken upToken = (UsernamePasswordToken) authenticationToken;
        String username = upToken.getUsername();
        String password = new String(upToken.getPassword());

        //2.根据用户名密码查询数据库,判断是否一致
        SysUser sysUser = sysUserService.login(username, password);

        //存在
        if(sysUser != null){
            //3.如果一致返回安全数据  构造方法 (安全数据,密码,realm域名)
            return new SimpleAuthenticationInfo(sysUser,sysUser.getPassword(),"CustomRealm");
        }

        //4.不一致,返回null,抛出异常
        return null;
    }
}

3. 配置shiro

在这里插入图片描述
代码如下:

package com.xxqy.shopping.config;

import com.xxqy.shopping.realm.CustomRealm;
import net.minidev.json.reader.BeansWriter;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;

/**
 * shiro配置
 * @Author yww
 * @CreateTime 2021-06-21
 */
@Configuration
public class ShiroConfig {

    //1.创建realm
    @Bean
    public CustomRealm getRealm(){
        return new CustomRealm();
    }

    //2.创建安全管理器
    @Bean
    public SecurityManager getSecurityManager(CustomRealm realm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setSessionManager(sessionManager());
        securityManager.setRealm(realm);
        return securityManager;
    }

    //3.配置shiro的过滤器工厂
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
        //1.创建过滤器工厂
        ShiroFilterFactoryBean filterFactory = new ShiroFilterFactoryBean();
        //2.设置安全管理器
        filterFactory.setSecurityManager(securityManager);
        //3.通用配置 (跳转登录页面,未授权跳转的页面)
        filterFactory.setLoginUrl("/login");//未登录跳转到登录页面
        filterFactory.setUnauthorizedUrl("/login");//未授权跳转到未授权页面
        //4.设置过滤器集合
        LinkedHashMap<String, String> filterMap = new LinkedHashMap<>();
        filterMap.put("/login","anon");//anon - 当前请求地址可以匿名访问 login页面
        filterMap.put("/static/**","anon");//静态资源
        filterMap.put("/sys/user/login","anon");//login请求

        filterMap.put("/**","authc");//authc - 当前请求地址必须认证之后可以访问

        filterFactory.setFilterChainDefinitionMap(filterMap);

        return filterFactory;
    }
    
    /**
     * 解决输入网址地址栏出现 jsessionid 的问题
     */
 	@Bean
    public DefaultWebSessionManager sessionManager(){
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        //解决输入网址地址栏出现 jsessionid 的问题
        sessionManager.setSessionIdUrlRewritingEnabled(false);
        return sessionManager;
    }

    /**
     * @RequiresPermissions(value = "permission::select")
     *   基于注解注解的配置方式进行授权,一旦操作用户不具备操作权限,目标方法不会被执行,并且会抛出AuthorizationException异常。
     */
    //4.开启对shiro注解的支持
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

    //注解生效2
    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator app=new DefaultAdvisorAutoProxyCreator();
        app.setProxyTargetClass(true);
        return app;
    }
    
	//shiro方言生效,thymeleaf中使用shiro标签库
    @Bean
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }

}

4. 登录
在这里插入图片描述
代码如下:

/**
     * shiro登录
     *      前端发送请求 => 接口部分获取用户名密码 => 通过subject.login => realm域的认证方法
     * @param username 用户名
     * @param password 密码
     * @param captcha 验证码
     * @return
     */
    @RequestMapping("/login")
    @ResponseBody
    public Rest loginDo(String username, String password, String captcha){
        try{
            //1.构造登录令牌
            UsernamePasswordToken upToken = new UsernamePasswordToken(username, password);
            //2.获取subject,执行getSubject()进入自定义realm认证
            Subject subject = SecurityUtils.getSubject();
            //3.调用subject进行登录
            subject.login(upToken);
            return Rest.ok().setMsg("登录成功");
        }catch (Exception e){
            e.printStackTrace();
            return Rest.error().setMsg("用户名或密码错误");
        }
    }

5. 注解授权

	//shiro注解授权
    @RequiresPermissions(value = "permission::select")
    @RequestMapping("/sysPermissionList")
    public String sysPermissionList(){
        return "sys/sysPermissionList";
    }

6. 因为使用shiro注解授权,没有权限会抛出AuthorizationException异常,所以要捕获特定异常

package com.xxqy.shopping.exception;

import org.apache.shiro.authz.AuthorizationException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 自定义公共异常处理类
 * @Author yww
 * @CreateTime 2021-06-21
 */
@ControllerAdvice
public class BaseExceptionHandler {

    /**
     * shiro注解授权,未拥有权限会报AuthorizationException异常
     * @param request
     * @param response
     * @param exception
     * @return
     */
    @ExceptionHandler(value = AuthorizationException.class)
    @ResponseBody
    public String error(HttpServletRequest request,HttpServletResponse response,AuthorizationException exception){
        return "未授权,不能访问!!!";
    }
}

效果图如下:
在这里插入图片描述
7. thymeleaf中使用shiro标签库判断权限

注意: 引入 xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"
shiro:hashPermission 为判断权限标签

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro" th:with="unixstamp=${#dates.createNow().time}">
<!--引用头部-->
<div th:include="common/common :: common"></div>

<body class="wholeBody">
        <!--vue区域-->
        <div id="app" v-cloak>
            <el-form :inline="true" :model="condition" class="demo-form-inline">
                <!--左侧搜索条件区域-->
                <el-form-item>
                    <el-input v-model="condition.username" placeholder="用户名"></el-input>
                </el-form-item>
                <el-form-item>
                    <el-button @click="search()">查询</el-button>
                </el-form-item>
                <!--右侧功能按钮区域-->
                <el-form-item style="float: right;">
                    <el-button shiro:hasPermission="sys-user-save" type="primary" @click="add()">添加</el-button>
                    <el-button shiro:hasPermission="sys-user-delete" type="danger" @click="batchRemove()">批量删除</el-button>
                    <el-button shiro:hasPermission="sys-user-bindingrole" type="danger" @click="bindingRole()" style="background-color: #4dc7d8;border-color: #4dc7d8;">绑定角色</el-button>
                </el-form-item>
            </el-form>
 
    <script type="text/javascript" th:src="@{/static/js/sys/sysUserList.js(v=${unixstamp})}"></script>

</body>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值