目录
简介
核心组件
springboot项目整合shiro
1、创建springboot应用
2、自定义过滤器
基础数据部分
用户认证
编写认证 和 授权 规则
认证过滤器规则:
授权过滤器规则:
案例
登陆认证
登陆授权
未授权显示
shiro整合thymeleaf
几张图片
简介
主流的java安全框架,可以不依赖任何容器,可以运行在javase和javaee项目中
官网:http://shiro.apache.org/
主要作用是对访问系统用户,进行身份认证,授权,会话管理,加密等常用操作
为什么用过滤器能实现的功能要用shiro?解决了什么问题?
业务比较分散的情况下,编写和管理过滤器的逻辑会复杂和繁杂,可维护性极差。需要结构化和工程化的方式,去解决大型项目安全性的问题。
shiro就是用来解决大型项目的安全管理的系统化框架
核心组件
一般会给 角色 赋予 权限 , 给用户 赋予 角色
1、UserNamePasswordTocken 封装用户的登陆信息,使用用户的登陆信息创建令牌
2、SecurityManager 负责安全认证 和 授权
3、Subject ,抽象了一个用户信息概念
4、Realm, 开发者自定义模块,根据项目需求 , 验证和授权实现在这里边
5、AuthenticationInfo 用户角色信息集合,支持认证时使用
6、AuthorzationInfo,用户角色的权限信息, 授权时使用
7、DefaultWebSecurityManager, 安全管理器,开发者自定义的Realm,需要注入到管理器中,进行管理才能生效
8、ShiroFilterFactoryBean, 过滤器工程,底层还是基于过滤器实现,开发者制定规则,shiro执行规则,具体的执行操作交给shiroFilterFactoryBean创建的Filter对象来完成
springboot项目整合shiro
1、创建springboot应用
<?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.3.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.zl</groupId>
<artifactId>boot02-shiro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>boot02-shiro</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-thymeleaf</artifactId>
</dependency>
<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>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.5.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2、自定义过滤器
基础数据部分
spring:
datasource:
name: springbootshiro
url: jdbc:mysql://localhost:3306/springbootshiro?useUnicode=true&characterEncoding=UTF-8
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
@Data
public class Accounter {
private Integer id;
private String username;
private String password;
private String perms;
private String role;
}
@Repository
public interface AccounterMapper extends BaseMapper<Accounter> {
}
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccounterMapper accounterMapper;
@Override
public Accounter findByUserName(String userName) {
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("username", userName);
return accounterMapper.selectOne(queryWrapper);
}
}
用户认证
实现部分
public class AccountRealm extends AuthorizingRealm {
@Autowired
private AccountService accountService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
/**
* 认证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken;
Accounter account = accountService.findByUserName(usernamePasswordToken.getUsername());
if(account != null) {
//密码验证
return new SimpleAuthenticationInfo(account, account.getPassword(), getName());
}
return null;
}
}
配置类部分,串通了shiro的路线
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean (@Qualifier("mysecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
return shiroFilterFactoryBean;
}
/**
* @Qualifier("accountRealm") 通过名字,从ioc容器里边拿到realm
* @param accountRealm
* @return
*/
@Bean
public DefaultWebSecurityManager mysecurityManager(@Qualifier("accountRealm") AccountRealm accountRealm) {
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
defaultWebSecurityManager.setRealm(accountRealm);
return defaultWebSecurityManager;
}
@Bean
public AccountRealm accountRealm() {
return new AccountRealm();
}
}
编写认证 和 授权 规则
认证过滤器规则:
anon 无须认证 、
authc 必须认证、
authcBase 需要通过HTTPBasic协议认证、
user 不一定通过认证,只要曾经被shiro记住了
授权过滤器规则:
perms 必须拥有某个权限才能访问
role 必须拥有某个角色才能访问
port 请求的端口必须为指定的值
rest 请求必须基于 Restful post、put、get、delete、
ssl 必须是安全的url请求,协议必须是https
案例
1、必须登陆才能访问main.html
2、当前用户必须拥有mananger授权才能访问manager.html
3、当前用户必须拥有administator这个角色才能访问administator.html
登陆认证
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean (@Qualifier("mysecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
//集合设置
Map<String,String> sourceMap = new HashMap<>();
shiroFilterFactoryBean.setLoginUrl("/login");
return shiroFilterFactoryBean;
}
@Controller
public class AccountController {
@GetMapping("/{url}")
public String redirect(@PathVariable("url") String url) {
return url;
}
@PostMapping("/login")
public String login(String username, String password, Model model) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);
try {
subject.login(usernamePasswordToken);
Account account = (Account)subject.getPrincipal();
subject.getSession().setAttribute("account",account);
return "index";
}catch (UnknownAccountException e) {
//用户不存在异常
model.addAttribute("msg","用户名错误" );
return "login";
}catch (IncorrectCredentialsException ie) {
//非法密码异常
model.addAttribute("msg","密码错误" );
return "login";
}
}
}
login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="shortcut icon" href="#"/>
</head>
<body>
<form action="/login" method="post">
<table>
<span th:text="${msg}" style="color: red"></span>
<tr>
<td>用户名:</td>
<td>
<input type="text" name="username" />
</td>
</tr>
<tr>
<td>密码:</td>
<td>
<input type="password" name="password" />
</td>
</tr>
<tr>
<td>
<input type="submit" value="登陆" />
</td>
</tr>
</table>
</form>
</body>
</html>
index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" >
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="shortcut icon" href="#"/>
</head>
<body>
<h1>index</h1>
<div th:if="${session.account != null}">
<span th:text="${session.account.username}+'欢迎回来!'"></span><a href="/logout">退出</a>
</div>
<a href="/main">main</a> <br/>
<a href="manage">manage</a> <br/>
<a href="/administrator">administrator</a>
</body>
</html>
登陆授权
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean (@Qualifier("mysecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
//集合设置
Map<String,String> sourceMap = new HashMap<>();
sourceMap.put("/main", "authc");
sourceMap.put("/manage", "perms[manage]");
sourceMap.put("/administrator", "roles[administrator]");
shiroFilterFactoryBean.setFilterChainDefinitionMap(sourceMap);
shiroFilterFactoryBean.setLoginUrl("/login");
return shiroFilterFactoryBean;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
Subject subject = SecurityUtils.getSubject();
Account account = (Account)subject.getPrincipal();
//设置角色
Set<String> setRole = new HashSet<>();
setRole.add(account.getRole());
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setRoles(setRole);
// 设置权限
info.addStringPermission(account.getPerms());
return info;
}
未授权显示
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean (@Qualifier("mysecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
//集合设置
Map<String,String> sourceMap = new HashMap<>();
sourceMap.put("/main", "authc");
sourceMap.put("/manage", "perms[manage]");
sourceMap.put("/administrator", "roles[administrator]");
shiroFilterFactoryBean.setFilterChainDefinitionMap(sourceMap);
shiroFilterFactoryBean.setLoginUrl("/login");
//设置未授权页面
shiroFilterFactoryBean.setUnauthorizedUrl("/unauth");
return shiroFilterFactoryBean;
}
@GetMapping("/unauth")
@ResponseBody
public String unauth(){
return "未授权,无法访问!";
}
shiro整合thymeleaf
1、依赖
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
2、配置类加入 方言识别
@Bean
public ShiroDialect shiroDialect(){
return new ShiroDialect();
}
3、html 命名空间
index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="shortcut icon" href="#"/>
</head>
<body>
<h1>index</h1>
<div th:if="${session.account != null}">
<span th:text="${session.account.username}+'欢迎回来!'"></span><a href="/logout">退出</a>
</div>
<a href="/main">main</a> <br/>
<div shiro:hasPermission="manage">
<a href="manage">manage</a> <br/>
</div>
<div shiro:hasRole="administrator">
<a href="/administrator">administrator</a>
</div>
</body>
</html>
几张图片