Spring Boot集成Shrio实现权限管理
- Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
- SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
- Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。用户一般会自定义Ream,集成AuthorizingRealm。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com</groupId>
<artifactId>springboot-shrio</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-shrio</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.13</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!--json-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.30</version>
</dependency>
<dependency>
<groupId>com.ibeetl</groupId>
<artifactId>beetl</artifactId>
<version>3.1.3.RELEASE</version>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>
package com.shiro.config; import com.shiro.realm.CustomRealm;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import java.util.HashMap;
import java.util.Map; /**
* @Author IT咸鱼
* @Date 2020/04/26
*/
@Configuration
public class ShiroConfig { private Logger logger = LoggerFactory.getLogger(this.getClass());
//不加这个注解不生效,具体不详
@Bean
@ConditionalOnMissingBean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
defaultAAP.setProxyTargetClass(true);
return defaultAAP;
} //将自己的验证方式加入容器
@Bean
public CustomRealm myShiroRealm() {
CustomRealm customRealm = new CustomRealm();
return customRealm;
} //权限管理,配置主要是Realm的管理认证
@Bean
public SecurityManager securityManager() {
logger.info("SecurityManager注册完成");
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
return securityManager;
} //Filter工厂,设置对应的过滤条件和跳转条件
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
logger.info("设置对应的过滤条件和跳转条件");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager); Map<String,String> map = new HashMap<String,String>();
// 配置不会被拦截的链接 顺序判断,因为前端模板采用了thymeleaf,这里不能直接使用 ("/static/**", "anon")来配置匿名访问,必须配置到每个静态目录
map.put("/css/**", "anon");
map.put("/fonts/**", "anon");
map.put("/img/**", "anon");
map.put("/js/**", "anon");
map.put("/html/**", "anon");
//配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
map.put("/logout", "logout");
//<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
//<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
map.put("/**", "authc");
// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
shiroFilterFactoryBean.setLoginUrl("/login");
// 登录成功后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl("/index"); //未授权界面;
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
} /**
* 开启shiro aop注解支持.
* 使用代理方式;所以需要开启代码支持;
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
package com.shiro.realm; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.shiro.entity.*;
import com.shiro.service.ITPermissionService;
import com.shiro.service.ITRoleService;
import com.shiro.service.ITUserService;
import com.shiro.service.LoginService;
import org.apache.catalina.authenticator.jaspic.SimpleAuthConfigProvider;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import java.util.List; public class CustomRealm extends AuthorizingRealm { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired
LoginService loginServiceImpl; @Autowired
ITUserService tUserServiceImpl; @Autowired
ITRoleService tRoleServiceImpl; @Autowired
ITPermissionService tPermissionServiceImpl; /**
* 授权
* @param principalCollection
* @return
* @throws AuthenticationException
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) throws AuthenticationException {
logger.info("CustomRealm.doGetAuthorizationInfo,PrincipalCollection={}", principalCollection);
TUser tUser = (TUser)principalCollection.getPrimaryPrincipal();
//添加角色和权限
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
List<TRole> roles = tRoleServiceImpl.getRoleByUserId(tUser.getId());
for (TRole tRole : roles){
authorizationInfo.addRole(tRole.getRoleCode());
List<TPermission> permissions = tPermissionServiceImpl.getPermissionsByRoleId(tRole.getId());
for (TPermission tPermission : permissions){
authorizationInfo.addStringPermission(tPermission.getPermissionCode());
}
}
return authorizationInfo;
} /**
* 用户调用登录接口时调用该方法,校验用户合法性
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
logger.info("CustomRealm.doGetAuthenticationInfo,AuthenticationToken={}", authenticationToken);
if (authenticationToken.getPrincipal() == null){
return null;
}
String userName = authenticationToken.getPrincipal().toString();
QueryWrapper<TUser> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(TUser::getUserName, userName);
TUser tUser = tUserServiceImpl.getOne(queryWrapper);
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
if (tUser == null){
throw new UnknownAccountException();
}
if (tUser.getStatus() == 0){
throw new LockedAccountException();
}
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(tUser, tUser.getPassword().toString(), getName());
return simpleAuthenticationInfo;
}
}
package com.shiro.controller; import com.shiro.dto.LoginDto;
import com.shiro.entity.TUser;
import com.shiro.entity.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import java.io.Serializable;
import java.util.Deque; @RestController
public class LoginController { private Logger logger = LoggerFactory.getLogger(this.getClass()); @RequestMapping("/login")
public String login(LoginDto loginDto) {
logger.info("/login, LoginDto={}", loginDto);
//添加用户认证信息
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(
loginDto.getUserName(),
loginDto.getPassword()
);
try {
//进行验证,这里可以捕获异常,然后返回对应信息
subject.login(usernamePasswordToken);
} catch (AuthenticationException e) {
e.printStackTrace();
return "账号或密码错误!";
} catch (AuthorizationException e) {
e.printStackTrace();
return "没有权限";
}
return "login success";
} @RequestMapping("/logout")
public String logout(){
logger.info("/logout");
Subject subject = SecurityUtils.getSubject();
if(null!=subject){
String username = ((TUser) SecurityUtils.getSubject().getPrincipal()).getUserName();
logger.info("username={}", username); }
return "logout success";
}
}
package com.shiro.controller; import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.shiro.common.ResultHandler;
import com.shiro.entity.TUser;
import com.shiro.service.ITUserService;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*; import java.util.List; /**
* <p>
* 前端控制器
* </p>
*
* @author xieya
* @since 2020-04-28
*/
@RestController
@RequestMapping("/user")
public class TUserController { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired
private ITUserService tUserServiceImpl; @RequiresRoles("admin")//指定需要有admin角色
@RequiresPermissions({"create","update"})//需要有create、update权限
@PostMapping("/save-or-update")
public String saveOrUpdate(@RequestBody TUser tUser){
logger.info("/save-or-update, TUser={}", tUser);
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject();
if (tUser == null){
return ResultHandler.handler(jsonObject, "-1001", "param null");
}
tUserServiceImpl.saveOrUpdate(tUser);
ResultHandler.handler(jsonObject, "0", "Success");
} catch (Exception e) {
logger.info("System Exception,e={}", e);
return ResultHandler.handler(jsonObject, "-9001", "System Exception");
}
return jsonObject.toString();
} @RequiresRoles("admin")
@RequiresPermissions("delete")
@GetMapping("/delete")
public String delete(Long id){
logger.info("/delete, id={}", id);
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject();
if (id == null){
return ResultHandler.handler(jsonObject, "-1001", "param null");
}
tUserServiceImpl.removeById(id);
ResultHandler.handler(jsonObject, "0", "Success");
} catch (Exception e) {
logger.info("System Exception,e={}", e);
return ResultHandler.handler(jsonObject, "-9001", "System Exception");
}
return jsonObject.toString();
} @PostMapping("/retrieve")
public String retrieve(@RequestBody TUser tUser){
logger.info("/retrieve, TUser={}", tUser);
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject();
if (tUser == null){
return ResultHandler.handler(jsonObject, "-1001", "param null");
}
QueryWrapper<TUser> queryWrapper = new QueryWrapper<>();
if (tUser.getId() != null){
queryWrapper.lambda().eq(TUser::getId, tUser.getId());
}
if (!StringUtils.isEmpty(tUser.getUserName())){
queryWrapper.lambda().eq(TUser::getUserName, tUser.getUserName());
}
List<TUser> list = tUserServiceImpl.list(queryWrapper);
ResultHandler.handler(jsonObject, "0", "Success", list);
} catch (Exception e) {
logger.info("System Exception,e={}", e);
return ResultHandler.handler(jsonObject, "-9001", "System Exception");
}
return jsonObject.toString();
}
}
登录之后使用postman去访问“/user/save-or-update”接口
如果在没有登录的情况下访问该接口,就会出现如下错误,在没有登录的请况下,shiro会自动的将接口访问重置到login接口login3
一个简单的小项目,希望能帮上大家
Spring Boot集成Shrio实现权限管理的更多相关文章
- spring boot集成shrio用于权限控制
下面是一个简单的springBoot集成shrio的项目,技术是:spring boot+idea+gradle+shrio+mybatis 1:首先在build.gradle中导入依赖 builds ...
- spring boot 2 + shiro 实现权限管理
Shiro是一个功能强大且易于使用的Java安全框架,主要功能有身份验证.授权.加密和会话管理.看了网上一些文章,下面2篇文章写得不错.Springboot2.0 集成shiro权限管理 Spring ...
- Spring Boot 集成Shiro和CAS
Spring Boot 集成Shiro和CAS 标签: springshirocas 2016-01-17 23:03 35765人阅读 评论(22) 收藏 举报 分类: Spring(42) 版 ...
- Spring boot集成RabbitMQ(山东数漫江湖)
RabbitMQ简介 RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统 MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法.应用程序通过读写出 ...
- 81. Spring Boot集成JSP疑问【从零开始学Spring Boot】
[原创文章,转载请注明出处] 针对文章: ()Spring Boot 添加JSP支持[从零开始学Spring Boot] 有网友提了这么一些疑问: 1.Spring Boot使用jsp时,仍旧可以打成 ...
- (37)Spring Boot集成EHCache实现缓存机制【从零开始学Spring Boot】
[本文章是否对你有用以及是否有好的建议,请留言] 写后感:博主写这么一系列文章也不容易啊,请评论支持下. 如果看过我之前(35)的文章这一篇的文章就会很简单,没有什么挑战性了. 那么我们先说说这一篇文 ...
- Spring boot集成Rabbit MQ使用初体验
Spring boot集成Rabbit MQ使用初体验 1.rabbit mq基本特性 首先介绍一下rabbitMQ的几个特性 Asynchronous Messaging Supports mult ...
- Spring Boot 集成阿里云 OSS 进行文件存储
最近因为项目中需要存储很多的图片,不想存储到服务器上,因此就直接选用阿里云的对象服务(Object Storage Service,简称 OSS)来进行存储,本文将介绍 Spring Boot 集成 ...
- 【SpringBoot】Spring Boot 集成SwaggerAPI
Spring Boot 集成SwaggerAPI 文章目录 Spring Boot 集成SwaggerAPI Swagger 添加依赖 配置类 config 控制类 controller 接口测试 页 ...
随机推荐
- USACO Training Section 1.3混合牛奶 Mixing Milk
题目描述 由于乳制品产业利润很低,所以降低原材料(牛奶)价格就变得十分重要.帮助Marry乳业找到最优的牛奶采购方案. Marry乳业从一些奶农手中采购牛奶,并且每一位奶农为乳制品加工企业提供的价格是 ...
- 数学--博弈论--巴什博奕(Bash Game)
终于也轮到我做游戏了,他们做了好几个月的游戏了. 巴什博弈: 两个人做游戏,取石子,一个人最多可以可以取M个,至少取1个,最后取完的赢. 显然,如果n=m+1,那么由于一次最多只能取m个,所以,无论先 ...
- P1495 CRT,P4777 EXCRT
updata on 2020.4.11 修正了 excrt 的一处笔误 CRT 求解方程: \[\begin{cases} x \equiv a_1 \pmod {m_1}\\ x \equiv a_ ...
- python json.dumps中ensure_ascii的使用,load与loads的区别
json模块最常用的两个功能: 一:json.dumps(),用于将dict拆分成str格式,称为序列化,注意序列化后,虽然print出来仍然显示的字典的样子,但是此时已经是str类型了. 其中,有时 ...
- ASP.NET Core的配置信息
ASP.NET Core的配置信息 Key-Value键值对 内存里.JSON.XML.INI等文件 配置信息与配置系统是解耦的 可以依赖注入 ASP.NET Core的配置信息来源 appsetti ...
- bootstrap栅格系统的使用
bootstrap栅格系统的使用 bootstrap栅格系统的使用,主要分为四种方式 1.列组合 col-md-* 2.列偏移 col-md-offset-* 3.列嵌套 大列组合包含着小组合 4 ...
- P2422 良好的感觉(两头单调)
描述:https://www.luogu.com.cn/problem/P2422 kkk做了一个人体感觉分析器.每一天,人都有一个感受值Ai,Ai越大,表示人感觉越舒适.在一段时间[i, j]内,人 ...
- 线段树 离散化 E. Infinite Inversions E. Physical Education Lessons
题目一:E. Infinite Inversions 这个题目没什么思维量,还比较简单,就是离散化要加上每一个值的后面一个值,然后每一个值放进去的不是1 ,而是这个值与下一个点的差值. 因为这个数代表 ...
- 记一次sqoop安装后测试的问题
运行命令: sqoop import --connect "jdbc:mysql://x.x.x.x:3306/intelligent_qa_bms?useUnicode=true& ...
- ActiveMQ 持久订阅者,执行结果与初衷相违背,验证离线订阅者无效,问题解决
导读 最新在接触ActiveMQ,里面有个持久订阅者模块,功能是怎么样也演示不出来效果.配置参数比较简单(配置没几个参数),消费者第一次运行时,需要指定ClientID(此时Broker已经记录离线订 ...