Shiro介绍
一款主流的java安全框架 不依赖任何容器
可以运行在javaSE 和java EE项目中,
主要作用对访问系统的用户进行身份认证(进行登录操作),
授权(拥有某些权限才可以进行访问某个模块),会话管理,加密操作。
Shiro 结构化 工程化 解决大型项目中的安全
Shiro 就是用来解决管理的系统化框架。
编写认证和授权规则
Anon 无需认证
Authc 必须认证
authcBasic 需要通过HTTPBasic认证
user 不一定通过认证 只要曾经被Shiro记录即可 比如 记住我
授权过滤器
Perms 必须拥有某个权限 才能访问
Role 必须拥有某个角色才能访问
Port 请求的端口必须是指定值才可以
Rest 请求必须基于Restful POST、PUT、GET、DELETE
Ssl 必须是安全的url请求 协议是https
用户、角色、权限
会给角色赋予权限 给用户赋予角色
1. UsernamePasswordToken Shiro 用来封装用户登录信息 使用用户的登录信息来创建令牌Token。
2. SecurityManager Shiro的核心部分 负责安全认证和授权。
3. Suject Shiro的一个抽象概念 包含了用户信息
4. Realm 开发者自定义模块 根据项目的需求 验证和授权的逻辑 全部卸载Realm中
5. Authenticationinfo 用户的角色信息集合 认证时使用
6. Authorzationinfo 角色的权限信息 授权时使用
7. DefaultWebSecurityManager 安全管理器
开发者自定义的Realm、需要注入到DefaultWebSecurityManager 进行管理才可以生效
8. ShiroFilterFactoryBean 过滤器工厂 Shiro的基本运行机制是开发者定制规则 Shiro去执行,具体的执行操作就是由ShiroFilterFactoryBean创建的一个个Filter 对象来完成的
自定义Shrio过滤器
对这个url进行拦截,需要先进行认证 根据需求判断对应的角色和权限
项目结构
pom.xml
<?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.6.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>SpringBoot_Shiro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SpringBoot_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.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1.tmp</version>
</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>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
ShiroConfig 配置类
// 配置类
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
factoryBean.setSecurityManager(securityManager);
// 权限设置
Map<String,String> map = new HashMap<>();
map.put("/main","authc");
map.put("/manage","perms[manage]");
map.put("/administrator","roles[administrator]");
// 通过这个map进行设置相对应的过滤器
factoryBean.setFilterChainDefinitionMap(map);
// 设置登录页面 发送这个请求 被视图解析器 捕获 跳转到login.html
factoryBean.setLoginUrl("/login");
// 设置未授权页面
factoryBean.setUnauthorizedUrl("/unauth");
return factoryBean;
}
@Bean
public DefaultWebSecurityManager securityManager(@Qualifier("accountRealm") AccountRealm accountRealm){
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
manager.setRealm(accountRealm);
return manager;
}
@Bean
public AccountRealm accountRealm(){
return new AccountRealm();
}
@Bean
public ShiroDialect shiroDialect(){
return new ShiroDialect();
}
}
AccountController 控制类
@Controller
//@RestController
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 subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
try {
subject.login(token);
return "index";
}catch (UnknownAccountException e){
e.printStackTrace();
model.addAttribute("msg","用户名错误");
return "login";
}catch (IncorrectCredentialsException e){
e.printStackTrace();
model.addAttribute("msg","密码错误");
return "login";
}
}
@GetMapping("/unauth")
@ResponseBody
public String unauth(){
return "未授权,无法访问";
}
}
AccountRealm realm自定义类
//自定义Realm
public class AccountRealm extends AuthorizingRealm {
@Autowired
private AccountService accountService;
// 用户的角色权限信息集合 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// 获取当前用户的信息
Subject subject = SecurityUtils.getSubject();
Account account = (Account) subject.getPrincipal();
// 设置角色
Set<String> roles = new HashSet<>();
roles.add(account.getRole());
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
// 设置权限
info.addStringPermission(account.getPerms());
return info;
}
// 用户的角色信息集合 登录
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
Account account = accountService.finByUseranme(token.getUsername());
if(account != null){
return new SimpleAuthenticationInfo(account,account.getPassword(),getName());
}
return null;
}
}
客户端拿到密码和用户名自动封装到token中 然后根据对应的用户名 进行查询 如果结果为null 表示没有该用户 跳出对密码的验证 Shiro会抛出 一个账户不存在
如果用户名存在 则开始验证密码 其中包括正确的密码 account.getPassword() 在和token中的密码 进行对比 在SimpleAuthenticationInfo这个方法总进行对比
运行结果展示
王三用户登录效果