基于SpringBoot2的Shiro最简配置操作(两个文件)

基础环境:依赖

<parent>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-parent</artifactId>
 <version>2.2.1.RELEASE</version>
 <relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
 <groupId>org.apache.shiro</groupId>
 <artifactId>shiro-spring-boot-starter</artifactId>
 <version>1.4.0</version>
</dependency>

如果不是前后端分离,要实现页面级的权限控制,则加入以下依赖就可以使用shiro的权限标签了(记得在html头部加上相应约束:

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="Thymeleaf" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"
  lang="en">
):
<dependency>
 <groupId>com.github.theborakompanioni</groupId>
 <artifactId>thymeleaf-extras-shiro</artifactId>
 <version>2.0.0</version>
</dependency>

Realm:认证鉴权器

package com.rz.monomer.modules.shiro;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.rz.monomer.modules.user.entity.SysUserInfo;
import com.rz.monomer.modules.user.entity.SysUserRole;
import com.rz.monomer.modules.user.service.SysButtonInfoService;
import com.rz.monomer.modules.user.service.SysUserInfoService;
import com.rz.monomer.modules.user.service.SysUserRoleService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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 java.util.Set;
import java.util.stream.Collectors;

/**
 * 认证、鉴权类(必须)
 *
 * @author sunziwen
 * @version 1.0
 * @date 2019/11/14 14:06
 **/
@Slf4j
public class ShiroRealm extends AuthorizingRealm {
 //以下三个服务是普通Dao查询,从数据库查询用户及其角色权限信息(这个类没有自动注入,需要在下个文件中手动注入)
 private SysUserInfoService userInfoService;
 private SysButtonInfoService buttonInfoService;
 private SysUserRoleService userRoleService;

 public ShiroRealm(SysUserInfoService userInfoService, SysButtonInfoService buttonInfoService, SysUserRoleService userRoleService) {
  this.userInfoService = userInfoService;
  this.buttonInfoService = buttonInfoService;
  this.userRoleService = userRoleService;
 }

 @Override
 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
  log.info("check authorization info");

  SimpleAuthorizationInfo authInfo = new SimpleAuthorizationInfo();

  // 获取当前用户
  SysUserInfo userInfo = (SysUserInfo) principals.getPrimaryPrincipal();

  // 查询角色信息
  Set<Long> userRoles = userRoleService.list(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userInfo.getId()))
            .stream()
            .map(SysUserRole::getRoleId)
            .collect(Collectors.toSet());
  //角色所有权限
  Set<String> perms = buttonInfoService.getPermsByRoles(userRoles);
  authInfo.addStringPermissions(perms);
  return authInfo;
 }

 @Override
 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
  log.info("check authentication info");

  String username = (String) token.getPrincipal();

  // 获取用户信息
  SysUserInfo user = userInfoService.getOne(new LambdaQueryWrapper<SysUserInfo>().eq(SysUserInfo::getUsername, username));

  if (user == null) {
   return null;
  }

  /*SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(),
    ByteSource.Util.bytes(654321), getName());*/

  SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), getName());
  return authenticationInfo;
 }
}

WebSecurityManager:安全管理器

package com.rz.monomer.modules.shiro;
import com.rz.monomer.modules.user.service.SysButtonInfoService;
import com.rz.monomer.modules.user.service.SysUserInfoService;
import com.rz.monomer.modules.user.service.SysUserRoleService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.filter.authc.LogoutFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Shiro配置类(必须)
 *
 * @author sunziwen
 * @version 1.0
 * @date 2019/11/14 14:08
 **/
@Configuration
@Slf4j
@AllArgsConstructor
public class WebSecurityManager {
 private SysUserInfoService userInfoService;
 private SysButtonInfoService buttonInfoService;
 private SysUserRoleService userRoleService;

 /**
  * 安全管理器
  */
 @Bean
 public DefaultWebSecurityManager securityManager() {
  DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
  securityManager.setRealm(realm());
  return securityManager;
 }

 /**
  * 认证鉴权器(安全管理器的依赖)
  */
 @Bean
 public ShiroRealm realm() {
  return new ShiroRealm(userInfoService, buttonInfoService, userRoleService);
 }

 /**
  * 配置拦截规则
  */
 @Bean
 public ShiroFilterFactoryBean filter(org.apache.shiro.mgt.SecurityManager securityManager) {
  log.info("config shiro filter");
  ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
  shiroFilterFactoryBean.setSecurityManager(securityManager);

  // 定义URL拦截链
  Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
  // 允许匿名用户访问首页
  filterChainDefinitionMap.put("/shiro/index", "anon");
  // 定义注销路径
  filterChainDefinitionMap.put("/shiro/logout", "logout");
  // 所有用户界面都需要身份验证,否则会跳转到loginurl,由FormAuthenticationFilter处理
  filterChainDefinitionMap.put("/shiro/user/**", "authc");
  // 为login路径定义拦截,由FormAuthenticationFilter处理
  filterChainDefinitionMap.put("/shiro/login", "authc");
  // 所有vip路径要求具备vip角色权限
  filterChainDefinitionMap.put("/shiro/vip/**", "roles[vip]");
  // 指定loginurl 路径
  shiroFilterFactoryBean.setLoginUrl("/shiro/login");
  // 登录成功后跳转路径
  shiroFilterFactoryBean.setSuccessUrl("/shiro/user/");
  // for un authenticated
  shiroFilterFactoryBean.setUnauthorizedUrl("/shiro/unauth");
  shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

  // 自定义filters,可覆盖默认的Filter列表,参考 DefaultFilter
  Map<String, Filter> filters = new LinkedHashMap<String, Filter>();

  // 定制logout 过滤,指定注销后跳转到登录页(默认为根路径)
  LogoutFilter logoutFilter = new LogoutFilter();
  logoutFilter.setRedirectUrl("/shiro/login");
  filters.put("logout", logoutFilter);

  // 定制authc 过滤,指定登录表单参数
  FormAuthenticationFilter authFilter = new FormAuthenticationFilter();
  authFilter.setUsernameParam("username");
  authFilter.setPasswordParam("password");
  filters.put("authc", authFilter);

  shiroFilterFactoryBean.setFilters(filters);
  return shiroFilterFactoryBean;
 }
}

Test:登录测试

package com.rz.monomer.modules.user.controller;
import com.rz.monomer.commons.utils.Md5Encrypt;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@RestController
@Slf4j
public class LoginController {
 @PostMapping("/login")
 public String login(@RequestParam("username") String username, @RequestParam("password") String password) {
  Subject subject = SecurityUtils.getSubject();
  AuthenticationToken token = new UsernamePasswordToken(username, Md5Encrypt.md5(password));

  try {
   // 执行登录
   subject.login(token);

  } catch (UnknownAccountException e) {

   // 未知用户
   log.warn("the account {} is not found", username);

   return "account not found";
  } catch (IncorrectCredentialsException e) {

   // 用户或密码不正确
   log.warn("the account or password is not correct");
   return "account or password not correct";

  }
  return "login success";
 }

}

补充:SpringBoot配置Shiro时踩坑

在SpringBoot2.0整合shiro时使用@EnableAutoConfiguration的时候需要对config文件进行扫描,即使用@ComponentScan对配置进行扫描。

或者直接使用@SpringBootApplication,但是这种方法会将主方法目录下的所有package都进行扫描影响项目效率。

Authentication failed for token submission [org.apache.shiro.authc.UsernamePasswordToken - zxc, rememberMe=false]. Possible unexpected error? (Typical or expected login exceptions should extend from AuthenticationException

当出现此异常时,一般情况是用户名密码不匹配,或者是在配置对应的Realm时出现空值导致匹配失败。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • 浅析SpringBoot2.4 静态资源加载问题

    标题index界面加载问题 刚开始学习springBoot记录一下遇到的小问题 1.index.html加载不出来的问题 我习惯性的将index.html放在public包下 而我使用了thymeleaf,它内置的视图解析器,屏蔽了springBoot的默认视图解析器,只会从templates包下读取视图资源,我将index.html拉到templates包下时就可以正常显示了 2.static包下静态资源加载不出来的问题 看了很多网上大多说的都是配置文件的问题,试了半天都不管用,静下心来从头整

  • springboot2.x整合tkmapper的示例代码

    springboot整合tkmapper 1.导入pom依赖 1.1 导入springboot的parent依赖 <parent> <artifactId>spring-boot-starter-parent</artifactId> <groupId>org.springframework.boot</groupId> <version>2.1.9.RELEASE</version> </parent> 1.

  • SpringBoot2.0整合Shiro框架实现用户权限管理的示例

    GitHub源码地址:知了一笑 https://github.com/cicadasmile/middle-ware-parent 一.Shiro简介 1.基础概念 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理.作为一款安全框架Shiro的设计相当巧妙.Shiro的应用不依赖任何容器,它不仅可以在JavaEE下使用,还可以应用在JavaSE环境中. 2.核心角色 1)Subject:认证主体 代表当前系统的使用者,就是用户,在Shiro的认证中,

  • SpringBoot2.0集成WebSocket实现后台向前端推送信息

    什么是WebSocket? WebSocket协议是基于TCP的一种新的网络协议.它实现了浏览器与服务器全双工(full-duplex)通信--允许服务器主动发送信息给客户端. 为什么需要 WebSocket? 初次接触 WebSocket 的人,都会问同样的问题:我们已经有了 HTTP 协议,为什么还需要另一个协议?它能带来什么好处? 答案很简单,因为 HTTP 协议有一个缺陷:通信只能由客户端发起,HTTP 协议做不到服务器主动向客户端推送信息. 举例来说,我们想要查询当前的排队情况,只能是

  • springboot2.x整合shiro权限框架的使用

    序 在实际项目中,经常需要用到角色权限区分,以此来为不同的角色赋予不同的权利,分配不同的任务.比如,普通用户只能浏览:会员可以浏览和评论:超级会员可以浏览.评论和看视频课等:实际应用场景很多.毫不夸张的说,几乎每个完整的项目都会设计到权限管理. 在 Spring Boot 中做权限管理,一般来说,主流的方案是 Spring Security ,但是由于 Spring Security 过于庞大和复杂,只要能满足业务需要,大多数公司还是会选择 Apache Shiro 来使用. 一般来说,Spri

  • 基于SpringBoot2的Shiro最简配置操作(两个文件)

    基础环境:依赖 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository -->

  • 基于SpringBoot2.0默认使用Redis连接池的配置操作

    SpringBoot2.0默认采用Lettuce客户端来连接Redis服务端的 默认是不使用连接池的,只有配置 redis.lettuce.pool下的属性的时候才可以使用到redis连接池 redis: cluster: nodes: ${redis.host.cluster} password: ${redis.password} lettuce: shutdown-timeout: 100 # 关闭超时时间 pool: max-active: 8 # 连接池最大连接数(使用负值表示没有限制

  • springmvc集成shiro登录失败处理操作

    一般的登录流程会有:用户名不存在,密码错误,验证码错误等.. 在集成shiro后,应用程序的外部访问权限以及访问控制交给了shiro来管理. shiro提供了两个主要功能:认证(Authentication)和授权(Authorization);认证的作用是证明自身可以访问,一般是用户名加密码,授权的作用是谁可以访问哪些资源,通过开发者自己的用户角色权限系统来控制. shiro的会话管理和缓存管理不在本文范围内. 下面通过登录失败的处理流程来介绍springmvc与shiro的集成. 依赖项目

  • 基于Tomcat 数据源的原理、配置、使用介绍

    1.数据源的作用及操作原理 在程序代码中使用数据源是可以提升操作性能的,这种性能的提升依靠于运行的原理. 传统JDBC操作步骤 1.加载数据库驱动程序,数据库驱动程序通过CLASSPATH配置: 2.通过DriverManager类取得数据库连接对象: 3.通过Connection实例化PreparedStatement对象,编写SQL命令操作数据库: 4.数据库属于资源操作,操作完成后进行数据库的关闭以释放资源.如图所示: 对于不同的用户只有操作不同,但是对于1.2.4三个步骤很明显是一个重复

  • Laravel5框架自定义错误页面配置操作示例

    本文实例讲述了Laravel5框架自定义错误页面配置操作.分享给大家供大家参考,具体如下: ♩ 背景 最近试着学习 laravel 5.5,使用 composer 下载新的框架源代码 composer create-project --prefer-dist laravel/laravel lar5Pro 5.5.* 发现在输入错误的链接时,会有如下的提示信息: 想到,一般成型的网站都会自定义404.501.503等页面,所以通过网上搜索方法,进行测试,可推荐如下的实现过程 - 框架: Lara

  • Laravel框架环境与配置操作实例分析

    本文实例讲述了Laravel框架环境与配置操作.分享给大家供大家参考,具体如下: Laravel 5 安装根目录下 .env 文件是配置文件.打开 config/database.php 可以看到,它返回一个PHP数组,该配置文件提供了各种数据库可能用到的配置.connections 里包含了数据库配置.修改'default' => 'mysql',参数可以选择需要使用的数据库. 'mysql' => [ 'driver' => 'mysql', 'host' => env('DB

  • Thinkphp 框架配置操作之动态配置、扩展配置及批量配置实例分析

    本文实例讲述了Thinkphp 框架配置操作之动态配置.扩展配置及批量配置.分享给大家供大家参考,具体如下: 动态配置 设置格式: C('参数名称','新的参数值') 例如,我们需要动态改变数据缓存的有效期的话,可以使用 // 动态改变缓存有效期 C('DATA_CACHE_TIME',60); 动态配置赋值仅对当前请求有效,不会对以后的请求造成影响. 动态改变配置参数的方法和读取配置的方法在使用上面非常接近,都是使用C方法,只是参数的不同. 也可以支持二维数组的读取和设置,使用点语法进行操作,

  • Thinkphp 框架配置操作之配置加载与读取配置实例分析

    本文实例讲述了Thinkphp 框架配置操作之配置加载与读取配置.分享给大家供大家参考,具体如下: 配置加载 在ThinkPHP中,一般来说应用的配置文件是自动加载的,加载的顺序是: 惯例配置->应用配置->模式配置->调试配置->状态配置->模块配置->扩展配置->动态配置 以上是配置文件的加载顺序,因为后面的配置会覆盖之前的同名配置(在没有生效的前提下),所以配置的优先顺序从右到左. 不同的配置文件的区别和位置: 惯例配置 惯例重于配置是系统遵循的一个重要思想

  • SpringBoot2.x的依赖管理配置

    前提 这篇文章是<SpringBoot2.x入门>专辑的第1篇文章,使用的SpringBoot版本为2.3.1.RELEASE,JDK版本为1.8. 主要梳理一下SpringBoot2.x的依赖关系和依赖的版本管理,依赖版本管理是开发和管理一个SpringBoot项目的前提. SpringBoot其实是通过starter的形式,对spring-framework进行装箱,消除了(但是兼容和保留)原来的XML配置,目的是更加便捷地集成其他框架,打造一个完整高效的开发生态. SpringBoot依

  • 基于Springboot2.3访问本地路径下静态资源的方法(解决报错:Not allowed to load local resource)

    最近在做的一个项目中有一个比较奇葩的需求: 要在springboot中,上传本地的图片进行展示 我的第一反应是,直接在数据库字段加一个存储本地路径的字段,然后用thymeleaf的th:src渲染到前端就好了嘛! 理想很丰满,但现实却很骨感~ 前端报了这样的错误Not allowed to load local resource 于是我想到了可以使用IO将图片先上传到static/images目录下,这样就不会出现禁止访问本地路径的问题了 但是这样实现,问题又来了:上传后的图片必须重启sprin

随机推荐