Shiro简介
什么是Shiro?
官网:https://shiro.apache.org/index.html
Apache Shiro™是一个功能强大且易于使用的 Java 安全框架,它执行身份验证、授权、加密和会话管理。借助 Shiro 易于理解的 API,您可以快速轻松地保护任何应用程序——从最小的移动应用程序到最大的 Web 和企业应用程序。
功能
验证
支持跨一个或多个可插入数据源(LDAP、JDBC、Active Directory…
授权
执行基于角色或细粒度权限的访问控制,也使用插件…
密码学
使用最简单的 Cryptography API 保护数据,为您提供…
会话管理
在任何环境中使用会话,甚至在 Web 或 EJB 容器之外。容易地…
网络集成
使用可轻松处理特定 Web 的创新方法节省开发时间…
集成
API 为您提供了超越 Java 默认提供的功能和简单性…
核心对象
Subject:当前公户(用户)
Shiro SecurityManage:管理所有Subjects。管理Subject(管理所有用户)
Realm:获得你的安全数据(链接数据)
基础操作
https://shiro.apache.org/10-minute-tutorial.html
// 获得当前用户
Subject currentUser = SecurityUtils.getSubject();
//拿到session
Session session = currentUser.getSession();
session.setAttribute( "someKey", "aValue" );
//判断当前用户是否被认证
currentUser.isAuthenticated()
// 获得当前用户
currentUser.getPrincipal()
// 当前用户角色
currentUser.hasRole( "schwartz" )
// 当前用户是否有权限
currentUser.isPermitted( "lightsaber:wield" )
// 注销
currentUser.logout();
springboot整合shiro
1.导入依赖
<!-- shiro权限依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!-- shiro ehcache -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.thymeleaf/thymeleaf-spring5 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-java8time -->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-java8time -->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
<version>3.0.4.RELEASE</version>
</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>
2.编写重点类UserRealm
UserRealm.java
import com.fxr.shirodemo.entity.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
public class UserRealm extends AuthorizingRealm {
// 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了=>授权doGetAuthorizationInfo");
// 给用户授予权限
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermission("user:add");
// 拿到当前登录用对象
Subject subject = SecurityUtils.getSubject();
//拿到user对象
User currentUser = (User) subject.getPrincipal();
// 设置当前用户的权限
info.addStringPermission(currentUser.getRole());
return info;
}
// 认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 用户名,密码 数据中取
String username = "root";
String password = "123";
String role = "user:add";
User user = new User(username,password,role);
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)authenticationToken;
// 用户名认证 抛出异常UnknownAccountException
if (!usernamePasswordToken.getUsername().equals(username)){
return null;
}
// 密码认证 shiro做
return new SimpleAuthenticationInfo(user,password,"");
}
}
3.编写配置类ShiroConfig
ShiroConfig.java
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;
@Configuration
public class ShiroConfig {
// 创建 realm对象,需要自定义:1
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
// DefaultWebSecurityManager:2
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager();
dwsm.setRealm(userRealm);
return dwsm;
}
// ShiroFilterFactoryBean:3
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean sffb = new ShiroFilterFactoryBean();
sffb.setSecurityManager(defaultWebSecurityManager);
/*** 添加shiro的内置过滤器
* anon 无需认证就可以访问
* authc 必须认证才能访问
* user 必须拥有记住我功能才能用
* perms 拥有对某个资源的权限才能访问
* role 拥有某个角色权限才能访问
* */
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
// user用户必须有add权限 401错误 正常会跳转到未授权
filterChainDefinitionMap.put("/add","perms[user:add]");
// filterChainDefinitionMap.put("/update","authc");
filterChainDefinitionMap.put("/update","perms[user:update]");
sffb.setFilterChainDefinitionMap(filterChainDefinitionMap);
// 被拦截的url后跳转到的请求地址
sffb.setLoginUrl("/toLogin");
// 未授权页面
sffb.setUnauthorizedUrl("/noauth");
return sffb;
}
}
4.编写页面
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>首页</h1>
<p th:text="${msg}"></p>
<a th:href="@{/add}">add</a> |
<a th:href="@{/update}">update</a>
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>首页</h1>
<p th:text="${msg}"></p>
<a th:href="@{/add}">add</a> |
<a th:href="@{/update}">update</a>
</body>
</html>
add.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>add</h1>
</body>
</html>
update.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>add</h1>
</body>
</html>
5.编写控制层类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;
@Controller
public class MyController {
@RequestMapping("/")
public String toIndex(Model model){
model.addAttribute("msg","hello,shiro");
return "index";
}
@RequestMapping("/add")
public String add(){
return "/add";
}
@RequestMapping("/update")
public String update(){
return "/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);
return "index";
} catch (UnknownAccountException e) { //用户名不存在
model.addAttribute("msg","用户名不存在");
return "login";
}catch (IncorrectCredentialsException e){ //密码不存在
model.addAttribute("msg","密码错误");
return "login";
}
}
@RequestMapping("/noauth")
public String unauthorized(){
return "error";
}
}