快速搭建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应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置 ...
随机推荐
- LeetCode--Sort Array By Parity && N-Repeated Element in Size 2N Array (Easy)
905. Sort Array By Parity (Easy)# Given an array A of non-negative integers, return an array consist ...
- 【Hadoop离线基础总结】Hadoop的架构模型
Hadoop的架构模型 1.x的版本架构模型介绍 架构图 HDFS分布式文件存储系统(典型的主从架构) NameNode:集群当中的主节点,主要用于维护集群当中的元数据信息,以及接受用户的请求,处理用 ...
- 【Hadoop离线基础总结】Hive的基本操作
Hive的基本操作 创建数据库与创建数据库表 创建数据库的相关操作 创建数据库:CREATE TABLE IF NOT EXISTS myhive hive创建表成功后的存放位置由hive-site. ...
- spark优化总结
1.Spark调优背景 目前Zeppelin已经上线一段时间,Spark作为底层SQL执行引擎,需要进行整体性能调优,来提高SQL查询效率.本文主要给出调优的结论,因为涉及参数很多,故没有很细粒度调优 ...
- 给bootstrap右边的菜单加上右键关闭
<ul class="rightmenu"> <li data-type="closethis">关闭当前</li> < ...
- Nuget一键打包上传以及高级应用
Nuget是什么不用多说,大家应该也没少用过Nuget, 不少人也应该使用过工具打Nuget包,接下来先一步步说明如何使用脚本完成Nuget一键打包 Nuget一键打包 配置Nuget环境 下载地址: ...
- SQL server 的使用中的subString() 和 charIndex() 实现筛选 某个字段的部分数据
subString(): SUBSTRING ( expression , start , length ) 参数expression 是字符串.二进制字符串.text.image.列或包含列的表达式 ...
- Bash Shell之内建命令和保留字
转载自:http://blog.chinaunix.net/uid-25880122-id-2941630.html 命令 含义 ! 保留字,逻辑非 : 不做任何事,只做参数展开 . 读取文件并在sh ...
- html,body设置高度100%后底部有空白的bug
html,body{ //... height:100% } #app{ //... } #footbar{ position:absolute;bottom:0px;left:0px;right:0 ...
- 微信小程序-视频弹幕的项目
1.视频播放器 2.选择弹幕颜色 3.弹幕来了... 一般微信小程序需要配置.wxml.wxss.js.json文件,所有接下来也是要配置这几个文件,请看下图: 第一: index.wxml < ...