首页 > 其他分享 >sringboot整合shiro实现前后端鉴权控制,标签注解速成(包含常见错误的出现,前后端注解标签详解应用)

sringboot整合shiro实现前后端鉴权控制,标签注解速成(包含常见错误的出现,前后端注解标签详解应用)

时间:2024-01-20 22:05:19浏览次数:35  
标签:return chain 标签 前后 new put 注解 权限 shiro


搭建shiro环境

1:导入boot项目中要用到的shiro依赖

<!--shiro部分-->
        <!--shiro核心源码-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.1</version>
        </dependency>
        <!--开启后端shiro标签支持-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <!--html中使用shiro标签-->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

2:编写shiro的配置类

作用:开启后端shiro注解(重要)

@Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor
                = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }

作用:启用shiro thymeleaf标签支持(重要)

/**
     * 启用shiro thymeleaf标签支持
     * @return
     */
    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }

作用:配置shiro的拦截器工厂bean(这里比较容易踩坑)

属性

含义

user

登录且访问对应的url有相应的权限角色才能访问

authc

必须认证了才能访问(进行鉴权)

anon

无需任何权限或者角色就可以访问

perms[]

指定的权限都要有才能访问

roles[]

指定的角色都要有才能访问

setUnauthorizedUrl

登录了但是没有相应权限时的跳转页面

setLoginUrl

设置没有登录时的默认跳转页面

setFilterChainDefinitionMap

设置资源访问权限(过滤规则)

setFilters

设置我们的自定义拦截器(应用于url)

@Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
          ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //这里一定要用LinkedHashMap避免设置的过滤规则乱序
        LinkedHashMap<String, String> chain = new LinkedHashMap<String, String>();
        //设置自定义拦截器
        LinkedHashMap<String, Filter> filters = new LinkedHashMap<>();
        filters.put("jwtFilter", new jwtFilter());
        //这些路径下的资源不需要权限
        chain.put("/login", "anon"); // 登录链接不拦截
        chain.put("/css/**", "anon");
        chain.put("/img/**", "anon");
        chain.put("/js/**", "anon");
        chain.put("/lib/**", "anon");
        chain.put("/needRole", "roles[zzh]");
        chain.put("/noNeedRole", "anon");
        chain.put("/unAuth", "anon");
        chain.put("/testCustomExpection", "anon");
        chain.put("/needPerms", "perms[zzhperms,zzhperms2]");
        chain.put("/noNeedPerms", "anon");
        //测试jwtFilter
        chain.put("/shiroCheck", "jwtFilter");
        //chain.put("/api/auth/**", "noSessionCreation,jwtFilter");
        //chain.put("/api/auth/**", "noSessionCreation");
        //其他路径需要权限,这个一定要写在最后,这样所有的过滤规则才会生效
        chain.put("/**", "authc");
        //设置资源访问权限
        bean.setFilterChainDefinitionMap(chain);
        bean.setSecurityManager(securityManager());
        //设置没有登录时的默认跳转页面
        bean.setLoginUrl("/login");
        //登录了但是没有相应权限时的跳转页面
        bean.setUnauthorizedUrl("/unAuth");
        bean.setFilters(filters);
        return bean;
    }

遇到的坑(设置的一些过滤规则不生效)

由于过滤链是从上往下顺序执行的,chain要用LinkedHashMap不要用hashMap,hashMap的存储是无序的可能chain.put("/**", “authc”);先遍历到了,其他的访问路径也就不需要访问拦截了

还没解决问题?

chain.put("/**", “authc”);这个记得一定要写在最后,这样所有的过滤规则才会生效

这些配置比较通用读者可以自行配置(比较机械的代码)

不做过多说明

@Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        // 注入安全管理器
        advisor.setSecurityManager(securityManager());
        return advisor;
    }

    /**
     * @param
     * @method 配置安全管理器
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setCacheManager(shiroCacheManager);
        securityManager.setRealm(loginRealm());
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

    /**
     * @param
     * @method 注入realm
     */
    @Bean
    public loginRealm loginRealm() {
        return new loginRealm();
    }

    /**
     * @param
     * @method DefaultWebSessionManager的配置
     */
    @Bean
    public SessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        SimpleCookie cookie = new SimpleCookie("myZzhSessionId");
        sessionManager.setSessionIdCookie(cookie);
        sessionManager.setSessionDAO(sessionDAO());
        return sessionManager;
    }

    /**
     * @param
     * @method 这里配置shiro的会话底层的缓存管理器,底层用的是redis
     */
    @Bean
    public SessionDAO sessionDAO() {
        shiroSessionDao shiroSessionDao = new shiroSessionDao(shiroCacheManager);
        return shiroSessionDao;
    }

编写测试controller

标签

属性

解释

@RequiresRoles

value = {“shiro”, “zzh”}, logical = Logical.OR

权限有一个就能访问此接口

@RequiresPermissions

value = {“add”, “select”}, logical = Logical.AND

权限都有才能访问此接口

@Controller
@RequestMapping("/testShiroAno")
public class testShiroAnoController {
    @RequiresPermissions("shiroAdd")
    @RequestMapping("/add")
    @RequiresRoles({"shiro"})
    public String add() {
        return "add";
    }

    @RequestMapping("/delete")
    @RequiresPermissions("shiroDelete")
    public String delete() {
        return "delete";
    }

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

    @RequiresRoles(value = {"shiro", "zzh"}, logical = Logical.OR)
    @RequestMapping("/select")
    @RequiresPermissions("shiroSelect")
    public String select() {
        return "select";
    }
}

编写测试loginRelam

当执行subject.login(token)的时候就会走我们Relam中的逻辑。这里我用的模拟数据,里面的逻辑如下。

用户

拥有的权限

拥有的角色

zzh

zzhperms和zzhperms2

zzh

shiro

shiroAdd和shiroDelete和shiroAlter

shiro

如果参数二是loginUser那么shiro会自动把loginUser中的password与参数二中的password作比较(我们无需编写比较密码的逻辑)

SimpleAuthenticationInfo

参数一

参数二

参数三

简单认证对象信息

认证的对象

数据库中的密码

就是realm的名称

simpleAuthorizationInfo

简单授权对象信息,我们可以对其赋予权限

public class loginRealm extends AuthorizingRealm {
    private Logger log = LoggerFactory.getLogger(loginRealm.class);
    /**
     * @param
     * @return
     * @function 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        log.info("授权。。。。。");
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        ArrayList<String> perms = new ArrayList<>();
        Object key = principals.getPrimaryPrincipal();
        loginUser loginUser = new loginUser();
        try {
            BeanUtils.copyProperties(loginUser, key);
        } catch (Exception e) {
        }
        //TODO这里是模拟数据库中的权限表的情况
        if (loginUser.getName().equals("shiro")) {
            perms.add("shiroAdd");
            perms.add("shiroDelete");
            perms.add("shiroAlter");
            simpleAuthorizationInfo.addRole("shiro");
            simpleAuthorizationInfo.addStringPermissions(perms);
        }
        if (loginUser.getName().equals("zzh")) {
            simpleAuthorizationInfo.addRole("zzh");
            perms.add("zzhperms");
            perms.add("zzhperms2");
            simpleAuthorizationInfo.addStringPermissions(perms);
        }
        log.info("授权完成。。。。。");
        return simpleAuthorizationInfo;
    }

    /**
     * @param
     * @return
     * @function 认证     doGetAuthenticationInfo
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        log.info("认证....");
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        // 1.获取用户输入的用户名
        String username = token.getUsername();
        // 2.获取用户输入的密码
        String password = new String(token.getPassword());
        loginUser loginUser = new loginUser();
        loginUser.setName(username);
        loginUser.setPassword(password);
        SimpleAuthenticationInfo info =
                new SimpleAuthenticationInfo(loginUser, "666", getName());
        log.info("认证完成....");
        return info;
    }
}

遇到的坑(获取PrimaryPrincipal信息的时候无法进行相应类型的对象转换)

这里我们直接暴力点用BeanUtils.copyProperties(loginUser, key);直接进行俩个对象间的属性赋值即可

权限,标签,注解对照表

测试的时候大家可以对着我这张参照表来对应着来看哦,铁质门(我现在就用过这么些shiro的标签,以后如果遇到过新的标签注解,再来补上来吧)

前端控制标签

作用

shiro:hasPermission

有此权限时显示按钮

shiro:hasAllPermissions

有全部权限时显示 按钮

shiro:hasAnyPermissions

有以下的任何一个权限时显示按钮

shiro:principal property=“name”

获取已经登录用户的name属性的值

data-shiro-principal property=“password”

获取已经登录用户的password属性的值

shiro:lacksPermission

与hasPermission标签逻辑相反,当前用户没有制定权限时,验证通过

shiro:lacksRole

与hasRole标签逻辑相反,当用户不属于该角色时验证通过。

shiro:user

认证通过登录过的用户

shiro:guest

没登录过的用户(访客)

后端控制注解

可选参数

解释

@RequiresRoles(value = {“shiro”, “zzh”}, logical = Logical.OR)

value(权限)logical(规则)

只有当前用户同时拥有shiro和zzh这俩个角色时才能访问这个接口

@RequiresPermissions(value = {“shiro”, “zzh”}, logical = Logical.OR)

value(权限)logical(规则)

只有当前用户同时拥有shiro和zzh这俩个权限时才能访问这个接口

开始准备测试

直接编写一个add.html(由于是boot项目相应的路由规则不再啰嗦)注意导入th shiro标签支持

<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">

sringboot整合shiro实现前后端鉴权控制,标签注解速成(包含常见错误的出现,前后端注解标签详解应用)_shiro


用shiro用户登录的效果图

sringboot整合shiro实现前后端鉴权控制,标签注解速成(包含常见错误的出现,前后端注解标签详解应用)_spring boot_02


用zzh用户登录的效果图(我这里是用了自定义异常,自定义异常传送门

sringboot整合shiro实现前后端鉴权控制,标签注解速成(包含常见错误的出现,前后端注解标签详解应用)_java_03


标签:return,chain,标签,前后,new,put,注解,权限,shiro
From: https://blog.51cto.com/u_16414043/9346298

相关文章

  • 注解版的springaop实操讲解(赋完整测试代码)
    aop是个很强的东西,我们可以用来实现日志收集,鉴权,敏感词过滤等等功能。在说注解版的springaop使用之前,一些专业术语我用大白话来复述一遍,希望大家不要嫌弃。切面:切入点+通知连接点:目标对象中被增强的某个方法切点:连接点的集合目标对象:被增强的对象织入:把代理逻辑加入到目标对象的过......
  • SpringMVC常用注解
    探索SpringMVC常用注解SpringMVC是一个用于构建Web应用程序的框架,它提供了丰富的注解来简化开发过程。在这篇文章中,我们将深入了解一些常用的SpringMVC注解,从它们的起因到实际应用。起因Web应用程序的开发涉及到处理HTTP请求和响应,传统的方式通常需要编写大量的XML配置和复杂的......
  • 死磕Spring之IoC篇 - 解析自定义标签(XML 文件)
    解析自定义标签(XML文件)上一篇《BeanDefinition的解析阶段(XML文件)》文章分析了Spring处理 org.w3c.dom.Document 对象(XMLDocument)的过程,会解析里面的元素。默认命名空间(为空或者 http://www.springframework.org/schema/beans)的元素,例如 <bean/> 标签会被解析成Generic......
  • 前后端都用得上的 Nginx 日常使用经验-补充篇
    之前分享了前后端都用得上的Nginx日常使用经验,在配置elk的时候增加了nginxbasicauth和IP百名的配置,作为补充分享。配置nginx域名转发常规的转发配置,不需要https部分去掉即可,一般只需要修改域名和转发地址server{listen80;listen443ssl;s......
  • SpringBoot项目通过注解快速解决,字典翻译,响应数据加密,数据脱敏等问题
    简介在几乎所有SpringBoot项目中都会面临字典翻译,接口数据加密,数据脱敏的问题。在每个接口中单独的解决会非常繁琐,因此接下来介绍一下怎么通过注解快速解决这些问题。实现步骤1.引入maven坐标<dependency><groupId>io.gitee.gltqe</groupId><artifactId>......
  • 多数据源事务——@DSTransactional注解原理
    1.前言在前面的文章中,提到一种手动提交多数据源事务的实现方式,dynamic-datasource包为我们提供了一种更为优雅,开箱即用的注解,即@DSTransactional,因为spring提供的@Tansactional注解是不支持多数据源的,@DSTransactional注解的出现刚好可以很好的弥补这一点。@DS注解和@DSTransacti......
  • 前后左右东西南北一年级儿歌
    前后左右东西南北一年级儿歌 2022-12-15 · TA获得超过782个赞关注前后左右东西南北一年级儿歌如下:1、早上起来了,面对大太阳,前面就是东方,后面就是西方,左面就是北方,右面就是南方。中午的时候太阳高高照面对着太阳,前面就是南方,后面就是北方,左面就是东方,右面就是西......
  • Nginx的前后端部署
    本篇主要介绍一下在window系统下Springboot+vue前后端分离的项目部署1.安装Nginx,官网下载安装即可,下载地址:https://nginx.org/en/download.html2.后端代码打包:在后端项目目录下执行:mvncleanpackage命令打包成功后会在项目目录下生成target文件夹3.前端代码打包:在前端项目......
  • dremio 基于Options注解的配置技巧
    以前简单写过一个dremio配置相关的介绍,以下是一个简单的使用原理dremio自己定义了一个Options的注解,包含此注解的类会被启动的时候进行类扫描加载,Options的会存储起来(分为不用类型的)有session级别的,系统级别的。。。。简单使用pom.xml <?xmlversion="1.......
  • 为什么要选择前后端分离?
    Python做全栈开发,其实有两种实现方式。一种就是前后端不分离的模式,通过Flask的模版语法来实现。但是这样做对前端的支持并不全面,另外大多数企业目前也摆脱了这样的模式。另一种就是前后端分离的模式,这是现在企业项目里经常采用的开发方式。为什么现在后者更常用呢,我们还得从项目......