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


猜你喜欢
- 本文介绍了springcloud Feign的Hystrix支持,分享给大家,具体如下:一、Feign client中加入Hystrix的f
- 先新建一个文件夹kun,kun就是类所在的package。新建一个java文件。HelloWorld.java的代码如下:package k
- 前言在Kotlin中四种可见性修饰符:private、protected、internal、public,如果没有显示指定修饰符的话,默认可
- 1.系统架构包括哪些形式?C/S架构B/S架构2.什么是C/S架构?说白了就是客户端/服务端,我们需要安装特定的客户端软卷,例如:QQ。C/
- 通过之前三篇关于Spring Boot异步任务实现的博文,我们分别学会了用@Async创建异步任务、为异步任务配置线程池、使用多个线程池隔离
- 1.企业实际项目中Git的使用在实际的企业项目开发中,我们一般Java的项目在公司都有自己的局域网代码仓库,仓库上存放着很多的项目。以我工作
- association和collection用法1.单个关联查询association1.1实体之间的关联表示package com.wor
- 问题(1)自己动手写一个锁需要哪些知识?(2)自己动手写一个锁到底有多简单?(3)自己能不能写出来一个完美的锁?简介本篇文章的目标一是自己动
- 这篇文章主要介绍了JAVA泛型的继承和实现、擦除原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的
- 一、文件上传概述实现Web开发中的文件上传功能,需要两步操作:1、在Web页面中添加上传输入项 <form
- 前言Spring Seuciry相关的内容看了实在是太多了,但总觉得还是理解地不够巩固,还是需要靠知识输出做巩固。相关版本:java: jd
- 本文实例为大家分享了C#基于Socket实现多人聊天功能的具体代码,供大家参考,具体内容如下服务器服务器负责接受所有客户端发来的消息,和将接
- 通过VideoView播放视频的步骤:1、在界面布局文件中定义VideoView组件,或在程序中创建VideoView组件2、调用Video
- 在springboot项目中如果要在不集成templates的情况下访问静态资源需要做以下配置1.在项目的application.yml文件
- 开篇我们还是和原来一样,讲一讲做爬虫的思路以及需要准备的知识吧,高手们请直接忽略。首先我们来缕一缕思绪,想想到底要做什么,列个简单的需求。需
- 本文实例讲述了Hibernate环境搭建与配置方法。分享给大家供大家参考,具体如下:1.下载hibernate jar包:hibernate
- 前言偶然逛国外博客,看到了一个介绍文字动画的库,进入 pub 一看,立马就爱上这个动画库了,几乎你能想到的文字动画效果它都有!现在正式给大家
- 要求:如下图,使用线程操作 1、实时显示当前时间 2、输入加数和被加数,自动出现结果 分析:两个问题解决的方式一致,使用子线程进
- 谜题在C#中,用virtual关键字修饰的方法(属性、事件)称为虚方法(属性、事件),表示该方法可以由派生类重写(override)。虚方法
- 1.嵌套函数业务开发中,我们可能会遇到这样一个场景:一个函数只会被某一处多次调用,且不想让这个函数在该类的其他地方调用,这个时候就需要对这个