Shiro
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
Shiro核心组件
用户、角色、权限
会给角色赋予权限 给用户赋予角色
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进行拦截,需要先进行认证 根据需求判断对应的角色和权限
SpringBoot整合Shiro
对应的数据库展示
项目结构
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]");
factoryBean.setFilterChainDefinitionMap(map);
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
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 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自定义类
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这个方法总进行对比
客户端拿到密码和用户名自动封装到token中 然后根据对应的用户名 进行查询 如果结果为null 表示没有该用户 跳出对密码的验证 Shiro会抛出 一个账户不存在
如果用户名存在 则开始验证密码 其中包括正确的密码 account.getPassword() 在和token中的密码 进行对比 在SimpleAuthenticationInfo这个方法总进行对比
运行结果展示
罗三用户登录效果
王三用户登录效果
|