SpringBoot整合Shiro实现登录认证的方法
作者:stackfing 发布时间:2022-03-23 01:12:19
安全无处不在,趁着放假读了一下 Shiro 文档,并记录一下 Shiro 整合 Spring Boot 在数据库中根据角色控制访问权限
简介
Apache Shiro是一个功能强大、灵活的,开源的安全框架。它可以干净利落地处理身份验证、授权、企业会话管理和加密。
上图是 Shiro 的基本架构
Authentication(认证)
有时被称为“登录”,用来证明用户是用户他们自己本人
Authorization(授权)
访问控制的过程,即确定“谁”访问“什么”
Session Management(会话管理)
管理用户特定的会话,在 Shiro 里面可以发现所有的用户的会话信息都会由 Shiro 来进行控制
Cryptography(加密)
在对数据源使用加密算法加密的同时,保证易于使用
Start
环境
Spring Boot 1.5.9 MySQL 5.7 Maven 3.5.2 Spring Data Jpa Lombok
添加依赖
这里只给出主要的 Shiro 依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.4.0-RC2</version>
</dependency>
配置
我们暂时只需要用户表、角色表,在 Spring boot 中修改配置文件将自动为我们创建数据库表
server:
port: 8888
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: root
url: jdbc:mysql://localhost:3306/shiro?characterEncoding=utf-8&useSSL=false
jpa:
generate-ddl: true
hibernate:
ddl-auto: update
show-sql: true
实体
Role.java
@Data
@Entity
public class Role {
@Id
@GeneratedValue
private Integer id;
private Long userId;
private String role;
}
User.java
@Data
@Entity
public class User {
@Id
@GeneratedValue
private Long id;
private String username;
private String password;
}
Realm
首先建立 Realm 类,继承自 AuthorizingRealm,自定义我们自己的授权和认证的方法。Realm 是可以访问特定于应用程序的安全性数据(如用户,角色和权限)的组件。
Realm.java
public class Realm extends AuthorizingRealm {
@Autowired
private UserService userService;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//从凭证中获得用户名
String username = (String) SecurityUtils.getSubject().getPrincipal();
//根据用户名查询用户对象
User user = userService.getUserByUserName(username);
//查询用户拥有的角色
List<Role> list = roleService.findByUserId(user.getId());
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
for (Role role : list) {
//赋予用户角色
info.addStringPermission(role.getRole());
}
return info;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//获得当前用户的用户名
String username = (String) authenticationToken.getPrincipal();
//从数据库中根据用户名查找用户
User user = userService.getUserByUserName(username);
if (userService.getUserByUserName(username) == null) {
throw new UnknownAccountException(
"没有在本系统中找到对应的用户信息。");
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(),getName());
return info;
}
}
Shiro 配置类
ShiroConfig.java
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
//以下是过滤链,按顺序过滤,所以/**需要放最后
//开放的静态资源
filterChainDefinitionMap.put("/favicon.ico", "anon");//网站图标
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(myRealm());
return defaultWebSecurityManager;
}
@Bean
public MyRealm myRealm() {
MyRealm myRealm = new MyRealm();
return myRealm;
}
}
控制器
UserController.java
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/")
public String index() {
return "index";
}
@GetMapping("/login")
public String toLogin() {
return "login";
}
@GetMapping("/admin")
public String admin() {
return "admin";
}
@PostMapping("/login")
public String doLogin(String username, String password) {
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
Subject subject = SecurityUtils.getSubject();
try {
subject.login(token);
} catch (Exception e) {
e.printStackTrace();
}
return "redirect:admin";
}
@GetMapping("/home")
public String home() {
Subject subject = SecurityUtils.getSubject();
try {
subject.checkPermission("admin");
} catch (UnauthorizedException exception) {
System.out.println("没有足够的权限");
}
return "home";
}
@GetMapping("/logout")
public String logout() {
return "index";
}
}
Service
UserService.java
@Service
public class UserService {
@Autowired
private UserDao userDao;
public User getUserByUserName(String username) {
return userDao.findByUsername(username);
}
@RequiresRoles("admin")
public void send() {
System.out.println("我现在拥有角色admin,可以执行本条语句");
}
}
展示层
admin.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<html lang="en"/>
<head>
<meta charset="UTF-8"/>
<title>Title</title>
</head>
<body>
<form action="/login" method="post">
<input type="text" name="username" />
<input type="password" name="password" />
<input type="submit" value="登录" />
</form>
</body>
</html>
home.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<html lang="en"/>
<head>
<meta charset="UTF-8"/>
<title>Title</title>
</head>
<body>
home
</body>
</html>
index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<html lang="en"/>
<head>
<meta charset="UTF-8"/>
<title>Title</title>
</head>
<body>
index
<a href="/login" rel="external nofollow" >请登录</a>
</body>
</html>
login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<html lang="en"/>
<head>
<meta charset="UTF-8"/>
<title>Title</title>
</head>
<body>
<form action="/login" method="post">
<input type="text" name="username" />
<input type="password" name="password" />
<input type="submit" value="登录" />
</form>
</body>
</html>
总结
这个小案例实现了根据角色来控制用户访问,其中最重要的就是 Realm,它充当了Shiro与应用安全数据间的“桥梁”或者“连接器”
来源:https://my.oschina.net/u/3726481/blog/1621946
猜你喜欢
- 一:hibernate-validator 基础1. 简介:通过使用注解Annotations 给类或者类的属性加上约束(constrain
- Environment的中文意思是环境,它表示整个spring应用运行时的环境信息,它包含两个关键因素profilespropertiesp
- 本文实例为大家分享了Java执行SQL脚本文件到数据库的具体方式,供大家参考,具体内容如下方式一:直接读取SQL脚本文件的内容,然后传递到S
- 最近在做上传文件的服务,简单看了网上的教程。结合实践共享出代码。由于网上的大多数没有服务端的代码,这可不行呀,没服务端怎么调试呢。Ok,先上
- 在logback.xml中加上该配置,包名如:com.xxx<logger name="packageName"
- JAVA常用关键字及其用法简要说明Abstract: 抽象的 一个Java语言中的关键字,用在类的声明中来指明一个类是不能被实例化的,但是可
- 这篇文章向大家分享了几段代码,主要是关于Thread+IO文件的加密解密,下面看看具体代码:加密启动线程package com.hz.sub
- 直接用英文逗号分隔就可以了,比如:inerface IHello { String sayHello(String name);
- 今天有个项目需要使用redis,并且有使用脚本的需求。但是因为之前没有写过,所以还有一点点不熟悉,今天记录一下。原因:原子操作,redis会
- 后台控制层: public static final String HEAD_IMG_DIR = "D:/upload/&quo
- 1、Java内存模型 Java虚拟机在执行程序时把它管理的内存分为若干数据区域,这些数据区域分布情况如下图所示:程序计数器:一块较小内存区域
- 我们编程的过程中大部分使用了很出色的ORM框架,例如:MyBatis,Hibernate,SpringJDBC,但是这些都离不开数据驱动JD
- redis redisson 集合操作相关类及接口Rlist:链表public interface RList<V> exten
- 一、BigInteger介绍如果在操作的时候一个整型数据已经超过了整数的最大类型长度 long 的话,则此数据就无法装入,所以,此时要使用
- 了解JVM内存结构的目的在Java的开发过程中,因为有JVM自动内存管理机制,不再需要像在C、C++开发那样手动释放对象的内存空间,不容易出
- spring-retry模块支持方法和类、接口、枚举级别的重试方式很简单,引入pom包<parent> <gr
- 1.特殊数组的特征值题目描述思路详解看到本题,首先思考需要排序,然后查找,这里为了效率采用二分查找。假设定义x=(left+riht)/ 2
- 前言中国象棋是起源于中国的一种棋,属于二人对抗 * 的一种,在中国有着悠久的历史。由于用具简单,趣味性强,成为流行极为广泛的棋艺活动。中国象
- 一、项目简述功能: 前后用户的登录注册,婚纱照片分类,查看,摄影师预 订,后台订单管理,图片管理等等。二、项目运行环境配置: Jdk1.8
- 首先先简单的说一下其3大特性的定义:封装:隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别。将抽象得到的数据和