综述:
Shiro框架是Apache旗下的一个开源项目,它是轻量级安全框架,非常简便易用,同Spring旗下的Security安全框架相比较,它更加简便,易用和灵活,没有Security复杂。Shiro包括:认证、授权、加密和会话管理等功能。
主要功能:
1、验证用户身份
2、用户授权,权限访问
3、支持单点登录(SSO)功能
4、提供记住我(Remember me)功能等
框架体系:
框架体系大概分为如下几种:
1、Authentication(认证):用户识别(你是谁)
2、AUthorization(授权):访问控制(你能干什么),也就是对访问权限的控制
3、Session Management(会话管理):对用户的会话管理
4、Cryptography(加密):对数据源的加密,防止进行窃取
主要流程:
在概念层,Shiro架构包含三个主要的理念:Subject、SecurityManager和Realm。下面将展示这三个组件如何相互作用。Shiro的执行流程图如下所示:
三个主要理念:
Subject:代表当前用户,Subject 可以是一个人,也可以是第三方服务、守护进程帐户、时钟守护任务或者其它当前和软件交互的任何事件。
SecurityManager:管理所有的Subject,SecurityManager是Shiro框架的核心,配合内部安全组件共同组成安全伞。
Realm:是进行权限信息的验证,这个需要我们自己去进行实现。它的本质就是一个特定的安全的Dao层:它封装了与数据源连接的细节,得到Shiro所需的相关数据。
在我们实现Realm的时候,需要继承AuthorizingRealm
类,重写AuthorizationInfo
(授权方法)和AuthenticationInfo
认证方法。
Spring Boot整合Shiro实例:
1、导入Shiro整合SpringBoot的依赖
代码如下所示:
<!--spring Boot和shiro的整合-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.1</version>
</dependency>
2、创建Shiro配置文件并且创建自定义Realm进行验证和授权
Realm的文件如下所示:
package com.ygl.config;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
/**
* @author ygl
* @description
* @date 2020/11/6 10:41
*/
//自定义的 UserRealm
public class UserRealm extends AuthorizingRealm {
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了授权功能=》doGetAuthorizationInfo!");
return null;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了认证功能=》doGetAuthorizationInfo!");
//用户名 密码 数据库中取
String name = "root";
String password = "123456";
UsernamePasswordToken userToken = (UsernamePasswordToken)token;
if (!userToken.getUsername().equals(name)){
//token中获取的name和数据中的name进行比较,如果不对返回null,shiro自动给我们进行捕获异常为用户名错误异常
return null;
}
//密码认证 shiro来进行操作,防止获取到密码
return new SimpleAuthenticationInfo("",password,"");
}
}
自定义Realm继承AuthorizingRealm类,重写doGetAuthorizationInfo(授权)和doGetAuthenticationInfo(验证)方法。这里未连接数据库,直接将用户和密码写死了,然后进行用户名验证和密码验证,密码验证直接交由Shiro进行验证,防止窃取密码。具体功能在注释中表明的有,请仔细看注释。
ShiroConfig配置如下所示:
package com.ygl.config;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author ygl
* @description
* @date 2020/11/6 10:37
*/
@Configuration
public class ShiroConfig {
//ShiroFilterFactoryBean 过滤 (第三步:连接到前端)
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
//配置shiro的内置过滤器
/*
anon:无需认证就可以访问
authc:必须认证才可以访问
user:必须拥有 记住我 功能才能访问
perms:拥有对某个资源的权限才能访问
role:拥有某个角色才能访问
*/
Map<String, String> filterMap = new LinkedHashMap();
filterMap.put("/toLogin","anon");
// filterMap.put("/user/add","authc");
// filterMap.put("/user/update","authc");
filterMap.put("/user/*","authc");
bean.setFilterChainDefinitionMap(filterMap);
//被拦截时 设置登录的请求
bean.setLoginUrl("/toLogin");
return bean;
}
//DafaultWebSecurityManager 安全对象 (第二步:接管对象)
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联userRealm
securityManager.setRealm(userRealm);
return securityManager;
}
//创建Realm对象 需要自定义 (第一步:创建对象)
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
}
注解@Configuration
一定要记得添加,getShiroFilterFactoryBean
方法、getDefaultWebSecurityManager
方法和userRealm
方法创建时进行一环套一环,一定要从第三个方法到第一个方法去创建。具体创建和理解,麻烦大家进行去看注释,注释里写的比较详细。
3、Controller层代码如下所示:
package com.ygl.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author ygl
* @description
* @date 2020/11/5 20:45
*/
@Controller
public class MyController {
@RequestMapping({
"/","/index"})
public String toIndex(Model model){
model.addAttribute("msg","hello,shiro");
return "index";
}
@RequestMapping("/user/add")
public String add(){
return "/user/add";
}
@RequestMapping("/user/update")
public String update(){
return "/user/update";
}
@RequestMapping("/toLogin")
public String toLogin(){
return "/login";
}
@RequestMapping("/login")
public String login(String username,String password,Model model){
//获取当前用户请求
Subject subject = SecurityUtils.getSubject();
//封装用户数据
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
subject.login(token);//执行登陆方法 , 如果没有异常就说明ok‘
return "index";
}catch (UnknownAccountException e){
//用户名不存在异常
model.addAttribute("msg","用户名错误");
return "login";
}catch (IncorrectCredentialsException e){
//密码错误
model.addAttribute("msg","密码错误");
return "login";
}
}
}
尤其注意login
方法,此方法中的subject.login(token),自动调用Shiro中的认证方法。我们只需要操作Realm中授权方法进行验证。
下面贴出pom文件和thymeleaf方面的html文件
pom文件:
<?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.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ygl</groupId>
<artifactId>shiro-springboot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>shiro-springboot</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--spring Boot和shiro的整合-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--thymeleaf模板-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
index.html代码:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>首页</h1>
<p th:text="${msg}"></p>
<hr>
<a th:href="@{/user/add}">添加</a>
<a th:href="@{/user/update}">更新</a>
</body>
</html>
login.html代码:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<p th:text="${msg}" style="color: red"></p>
<h1>登录页面</h1>
<hr>
<form th:action="@{/login}">
<p>用户名:<input type="text" name="username"></p>
<p>密码:<input type="text" name="password"></p>
<p><input type="submit"></p>
</form>
</body>
</html>
update.html代码:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>更新页面</title>
</head>
<body>
<h1>update</h1>
</body>
</html>
add.html代码如下所示:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>添加页面</title>
</head>
<body>
<h1>添加</h1>
</body>
</html>
大家有那些不懂的,欢迎在下方评论