快速搭建Spring Boot + Apache Shiro 环境
个人博客网:https://wushaopei.github.io/ (你想要这里多有)
一、Apache Shiro 介绍及概念
概念:Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
Shiro 框架图:

框架图解析:
Primary Concerns四部分: 用户识别、授权、会话管理、加密
Supporting Features 五部分: Shiro特有的API、缓存、 并发、测试、Run As 、Remember Me
Shiro 概念层 架构:

应用代码经过 Subject 进行简单授权和认证, Subject 又委托给SecurityManager
二、Apache Shiro 部分功能讲解:
1、Apache Shiro授权讲解

- 首先调用Subject 进行处理,再委托给 Security Manageer ,Security Manageer会委托给 Authorizer ,Authorizer是真正的授权者。
Shiro 的授权主要包含四个核心:主体、资源、权限、角色
主体: 访问应用的用户,用户只有授权后才能访问到相应的资源
资源: 查看、编辑某个数据,读取某个文本等都是资源
权限: 建立在资源以及操作上,只限定能做什么
角色: 才是真正可以对主体的权限进行分配的核心
2、 Apache Shiro权限拦截框架图:

3、Apache Shiro会话管理框架图

会话管理主要是管理所有会话的创建、查询、交互等。
三、基于SpringBoot的Apache Shiro环境快速搭建与配置
1、环境搭建及使用
主要涉及两点:
- 快速搭建Spring Boot + Apache Shiro 环境
- 常用Case实现
(1)创建springboot 工程 Spring-boot_Shiro ,整合 Shiro 依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.20</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
(2)创建数据库表结构 : user 、role、permission、permission_role、user_role、五张表;
CREATE TABLE `user` (
`uid` int(11) NOT NULL AUTO_INCREMENT ,
`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' ,
`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' ,
PRIMARY KEY (`uid`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
AUTO_INCREMENT=3
ROW_FORMAT=DYNAMIC;
CREATE TABLE `role` (
`rid` int(11) NOT NULL AUTO_INCREMENT ,
`rname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' ,
PRIMARY KEY (`rid`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
AUTO_INCREMENT=3
ROW_FORMAT=DYNAMIC;
CREATE TABLE `permission` (
`pid` int(11) NOT NULL AUTO_INCREMENT ,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' ,
`url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' ,
PRIMARY KEY (`pid`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
AUTO_INCREMENT=1
ROW_FORMAT=DYNAMIC;
CREATE TABLE `permission_role` (
`rid` int(11) NOT NULL ,
`pid` int(11) NOT NULL ,
INDEX `idx_rid` (`rid`) USING BTREE ,
INDEX `idx_pid` (`pid`) USING BTREE
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
ROW_FORMAT=DYNAMIC;
CREATE TABLE `user_role` (
`uid` int(11) NOT NULL ,
`rid` int(11) NOT NULL ,
INDEX `idx_uid` (`uid`) USING BTREE ,
INDEX `idx_pid` (`rid`) USING BTREE
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
ROW_FORMAT=DYNAMIC;
(3)创建 user、role、permission 三个类
public class User {
private String username;
private Integer uid;
private String password;
private Set<Role> roles = new HashSet<>();
。。。。。。。。。。。。
}
public class Role {
private Integer rid;
private String rname;
private Set<Permission> permissionSet = new HashSet<>();
...................
}
public class Permission {
private Integer pid;
private String name;
private String url;
。。。。。。。。。。。。。。
}
(4)创建service业务层、mapper 持久层
service 、serviceimpl业务接口及实现类
public interface UserService {
User findByUsername(String username);
}
@Service
@Transactional(readOnly=true)
public class UserServiceimpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User findByUsername(String username) {
return userMapper.findByUsername(username);
}
}
UserMapper.java 持久层
@Component
@Mapper
public interface UserMapper {
User findByUsername(@Param("username") String username);
List<User> getAll();
}
UserMapper.xml
<mapper namespace="com.webcode.springboot.mappers.UserMapper">
<resultMap id="userMap" type="com.webcode.springboot.entities.User">
<id property="uid" column="uid"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
<collection property="roles" ofType="com.webcode.springboot.entities.Role">
<id property="rid" column="rid"/>
<result property="rname" column="rname"/>
<collection property="permissionSet" ofType="com.webcode.springboot.entities.Permission">
<id property="pid" column="pid"/>
<result property="name" column="name"/>
<result property="url" column="url"/>
</collection>
</collection>
</resultMap>
<select id="findByUsername" parameterType="string" resultMap="userMap">
SELECT u.*,r.*,p.*
from user u
INNER JOIN user_role ur on ur.uid = u.uid
INNER JOIN role r on r.rid = ur.rid
INNER JOIN permission_role pr on pr.rid = r.rid
INNER JOIN permission p on pr.pid = p.pid
WHERE u.username = #{username}
</select>
<select id="getAll"
resultMap="userMap">
select *
from USER
</select>
</mapper>
(5)配置mapper.xml 包扫描位置及对应的javabean 所在包,用于mapper.xml的映射
application.yml 配置文件:
mybatis:
mapper-locations: classpath*:/mybatis/mappers/*Mapper.xml #包扫描 mapper.xml 类
type-aliases-package: com.webcode.springboot.entities # 指定相应 mapper.xml 中实体 javabean 的所在位置
server:
port: 8081
Bootstrap 启动类:
//扫描Mapper接口
@MapperScan("com.webcode.springboot.mappers")
@ComponentScan({"com.webcode.springboot"})
@SpringBootApplication
public class Bootstrap { public static void main(String[] args) {
SpringApplication.run(Bootstrap.class, args);
}
}
2、基于Apache Shiro权限管理Case -- 认证授权配置
创建自定义的 AuthRealm 类,该类 继承 AuthorizingRealm 类,并重写doGetAutherizationInfo(PrincipalCollection principals) 和 doGetAuthenticationInfo(AuthenticationToken token) 两个方法 分别 作为授权和认证登录所用;
public class AuthRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 授权要先从 session 取出对象来
User user = (User) principals.fromRealm(this.getClass().getName()).iterator().next();
List<String> permissionList = new ArrayList<>();
Set<Role> roleSet = user.getRoles();
if (CollectionUtils.isNotEmpty(roleSet)){
for (Role role : roleSet) {
Set<Permission> permissionSet = role.getPermissionSet();
if (CollectionUtils.isNotEmpty(permissionSet)){
for (Permission permission : permissionSet) {
permissionList.add(permission.getName());
}
}
}
}
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.addStringPermissions(permissionList);
return null;
}
// 认证登录
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token; //将Token 降为 usernamePasswordToken
String username = usernamePasswordToken.getUsername(); //去除其中的username
User user = userService.findByUsername(username); //根据username 查询到 user 信息
return new SimpleAuthenticationInfo(user,user.getPassword(),this.getClass().getName());
}
}
3、基于Apache Shiro权限管理Case -- 密码规则校验器
说明:
因为密码是直接取得数据库的密码,所以想要保证用户传入的密码能和我的密码能够匹配,需要创建自定义的密码校验规则。
具体:通过重写CredentialsMatcher 类,继承SimpleCredentialsMatcher类,重新定义 密码校验规则的重写
/**
* @ClassName CredentialMatcher 密码校验规则的重写
* @Description TODO
* @Author wushaopei
* @Date 2019/9/24 10:07
* @Version 1.0
*/
public class CredentialMatcher extends SimpleCredentialsMatcher {
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
UsernamePasswordToken token1 = (UsernamePasswordToken) token;
String passsword = new String(token1.getPassword());
String dbPassword = (String) info.getCredentials();
return this.equals(passsword,dbPassword);
}
}
4、基于Apache Shiro权限管理Case -- Shiro配置
创建 ShiroConfiguration 类 ,该类是 shiro 的配置类
@Configuration
public class ShiroConfiguration {
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager manager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
// 必须设置 SecurityManager
bean.setSecurityManager(manager);
// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
bean.setLoginUrl("/login");
// 登录成功后要跳转的链接
bean.setSuccessUrl("/index");
// 未授权界面;
bean.setUnauthorizedUrl("/unauthorized");
// 拦截器.
LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/index","authc");
filterChainDefinitionMap.put("/login","anon");
bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return bean;
}
//配置核心安全事务管理器
@Bean("securityManager")
public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 设置realm.
securityManager.setRealm(authRealm);
return securityManager;
}
//配置自定义的权限登录器
@Bean("authRealm")
public AuthRealm authRealm(@Qualifier("credentialMatcher")CredentialMatcher matcher){
AuthRealm authRealm = new AuthRealm();
authRealm.setCredentialsMatcher(matcher); //给出自定密码比较器
return authRealm; //返回自定Realm
}
//配置自定义的密码比较器
@Bean("credentialMatcher") //生成 密码校验规则的Bean
public CredentialMatcher credentialMatcher(){
return new CredentialMatcher(); //返回密码校验规则实例
}
/**
* 开启shiro aop注解支持. 使用代理方式;所以需要开启代码支持; Controller才能使用@RequiresPermissions
*
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager")SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true);
return creator;
}
}
5、定义请求接口:包括首页、登录页、异常页面
@RequestMapping("/login")
public String login(){
return "login";
}
@RequestMapping("/index")
public String index(){
return "index";
}
@RequestMapping("/loginUser")
public String loginUser(@RequestParam("username")String username,
@RequestParam("password") String password,
HttpSession session){
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
Subject subject = SecurityUtils.getSubject();
try {
subject.login(token);
User principal = (User) subject.getPrincipal();
session.setAttribute("user",principal);
return "index";
}catch (Exception e){
return "login";
}
}
6、定义jsp 页面,包括index.jsp、login.jsp、
jsp 相关配置:在 yml 文件中,申明jsp的前缀、后缀
spring:
mvc: ## jsp ##
view:
prefix: /pages/
suffix: .jsp
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Login</title>
</head>
<body>
<h1>欢迎登录</h1>
<form action="/loginUser" method="post">
<input type="text" name="username"><br>
<input type="password" name="password"><br>
<input type="submit" value="提交"><br>
</form>
</body>
</html>
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index</title>
</head>
<body>
<h1>欢迎登录, ${user.username}</h1>
</body>
</html>
接口登录测试:

提交,认证通过

7、基于Apache Shiro权限管理Case -- Shiro配置 登录拦截
shiro 过滤器添加配置:
filterChainDefinitionMap.put("/loginUser","anon"); //登陸不用登陸認證
filterChainDefinitionMap.put("/**","user"); //其他接口要驗證是否登陸過用戶
测试:

除了登录功能不需要进行认证外,其他接口请求都需要进行用户是否登录的认证.
8、基于Apache Shiro权限管理Case -- Shiro配置 角色认证
在 ShiroConfiguration.java 进行配置:
filterChainDefinitionMap.put("/admin","roles[admin]"); //授权过程中认证角色为admin的用户才可以访问
在AuthRealm.java进行配置:
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 授权要先从 session 取出对象来
User user = (User) principals.fromRealm(this.getClass().getName()).iterator().next();
List<String> permissionList = new ArrayList<>();
List<String> roleNameList = new ArrayList<>(); //角色授权拦截。。。。。。。
Set<Role> roleSet = user.getRoles();
if (CollectionUtils.isNotEmpty(roleSet)){
for (Role role : roleSet) {
roleNameList.add(role.getName()); //角色授权拦截。。。。。。。。
Set<Permission> permissionSet = role.getPermissionSet();
if (CollectionUtils.isNotEmpty(permissionSet)){
for (Permission permission : permissionSet) {
permissionList.add(permission.getName());
}
}
}
}
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.addStringPermissions(permissionList);
simpleAuthorizationInfo.addRoles(roleNameList); //角色授权拦截。。。。。。
return simpleAuthorizationInfo;
}
8、基于Apache Shiro权限管理Case -- Shiro配置 permission 认证
说明:具有指定 permission 功能的permission才可以访问,如有edit时,才可以访问,否则不能访问
在ShiroConfiguration.java类中 shiroFilter 方法中配置:
filterChainDefinitionMap.put("/edit","perms[edit]");//具有edit 的pemission 才可以访问
快速搭建Spring Boot + Apache Shiro 环境的更多相关文章
- 基于 intellij IDEA 快速搭建Spring Boot项目
在<一步步搭建 Spring Boot maven 框架的工程>一文中,已经介绍了如何使用Eclipse快速搭建Spring Boot项目.由于最近将开发工具由Eclipse ...
- 快速搭建Spring Boot项目
Spring boot是Spring推出的一个轻量化web框架,主要解决了Spring对于小型项目饱受诟病的配置和开发速度问题. Spring Boot 包含的特性如下: 创建可以独立运行的 Spri ...
- Spring boot入门(一):快速搭建Spring boot项目
(一)Spring boot介绍 本部分摘自:https://www.zhihu.com/question/64671972/answer/223383505 Spring Boot是由Pivotal ...
- 构建微服务:快速搭建Spring Boot项目
Spring Boot简介: Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员 ...
- SpringBoot学习(一)—— idea 快速搭建 Spring boot 框架
简介 优点 Spring Boot 可以以jar包的形式独立运行,运行一个Spring Boot 项目只需要通过 java -jar xx.jar 来运行. Spring Boot 可以选择内嵌Tom ...
- cas 3.5.3服务器搭建+spring boot集成+shiro模拟登录(不修改现有shiro认证架构)
因为现有系统外部接入需要,需要支持三方单点登录.由于系统本身已经是微服务架构,由多个业务独立的子系统组成,所以有自己的用户认证微服务(不是cas,我们基础设施已经够多了,现在能不增加就不增加).但是因 ...
- [转载]快速搭建Spring MVC 4开发环境
(一)工作环境准备: JDK 1.7 Eclipse Kepler Apache Tomcat 8.0 (二)在Eclipse中新建Maven工程,在Archetype类型中,选择“maven-arc ...
- 使用idea搭建Spring boot开发初始环境
准备工作 将以下代码加入idea的live template,命名为springbootStartup <parent> <groupId>org.springframewor ...
- 使用IDEA搭建Spring Boot入门项目
简介 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置 ...
随机推荐
- 软路由OpenWrt(LEDE)2020.5.10更新 UPnP+NAS+多拨+网盘+DNS优化
近期更新:2020.05.10更新-基于OpenWrt R2020.5.9版本,源码截止2020.05.10. 交流群:QQ 1030484865 电报 t.me/t_homelede 版本说 ...
- redis 集群安装
redis集群安装 1.下载redis源码 2.解压并进入解压后的文件夹redis内 3.make,生成一系列的文件(mkreleasehdr.sh, redis-benchmark, redis-c ...
- [hdu2119]二分图最小覆盖,最大匹配
题意:给一个01矩阵,每次可以选一行或一列,打掉上面所有的1,求打掉所有的1所需的最小次数. 思路:经典的模型了,二分图最小覆盖=最大匹配.所谓最小覆盖是指选最少的点关联所有的边.容易得到将行和列看成 ...
- Luogu P3846 BSGS算法
https://www.luogu.com.cn/problem/P3846 BSGS这个东西是用来干啥的? 形如下面这个式子: \[a^b = c\;(mod\;p) \] 其中:p是一个质数.\( ...
- Centos7 下代理配置
对于提供服务的服务器来说,一般都配置在内网环境中,而在内网下公司处于安全的考虑,一般不开放外网的访问权限.这时如果想要访问外网,一般需要配置公司提供的代理服务器再进行使用.下面介绍几种配置代理的方法: ...
- spark机器学习从0到1奇异值分解-SVD (七)
降维(Dimensionality Reduction) 是机器学习中的一种重要的特征处理手段,它可以减少计算过程中考虑到的随机变量(即特征)的个数,其被广泛应用于各种机器学习问题中,用于消除噪声 ...
- node响应头缓存设置
我把react项目分成4个板块,在路由的顶层 今天在手机上打开react项目的时候,发现平级路由跳转时某一个图片较多的板块图片总是渲染得很慢,这分明是重新发起请求了. 然后我先查一下react-rou ...
- 3.1Go变量
3.1 Go变量 变量是对内存中数据存储空间的表示,如同门牌号对应着房间,同样的,变量名字对应变量的值. 变量:本质就是一块内存空间.用于存储某个数值.该数值在运行时可以改变. 变量使用步骤 1.声明 ...
- Django之MTV模式
MTV与MVC+url控制器 MVC框架: · M:model.py 就是和数据库打交道用的,创建表等操作 · V:View 视图(视图函数:逻辑处理响应函数,ht ...
- removebg抠图小工具
由于比较简单,直接上代码(removebg接口官网),更多小工具获取 (1)官网API,需注册获取X-Api-Key:removebg_官网api.py import requests respons ...