1、Shiro
用来做登录认证以及权限管理
2、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 对象来完成。
3、Spring Boot 整合 Shiro
创建 3 个页面,main.html、manager.html、administrator.html
访问权限如下:
1、必须登录才能访问 main.html
2、当前用户必须拥有 manager 授权才能访问 manage.html
3、当前用户必须拥有 administrator 角色才能访问 administrator.html
1、前台页面
主页index
<!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>
<span><a href="/logout">退出</a></span>
</div>
<a href="/main">main</a>
<a href="/manager">manager</a>
<a href="/administrator">administrator</a>
</body>
</html>
登录页login
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="shortcut icon" href="#"/>
</head>
<body>
<h1>login</h1>
<!--错误信息提示-->
<span style="color: chartreuse" th:text="${msg}"></span>
<form action="/login" method="post">
<table>
<tr>
<td>用户名</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密 码</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td><button type="submit">登录</button></td>
</tr>
</table>
</form>
</body>
</html>
权限页面
main.html 必须
登录
才能访问
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="shortcut icon" href="#"/>
</head>
<body>
<h1>main</h1>
</body>
</html>
manager 必须拥有manager
权限
才能访问
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="shortcut icon" href="#"/>
</head>
<body>
<h1>manager</h1>
</body>
</html>
administrator 必须拥有administrator
角色
才能访问
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="shortcut icon" href="#"/>
</head>
<body>
<h1>administrator</h1>
</body>
</html>
2、后台处理
1、pom.xml
<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.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.5.3</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.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>
2、编写Realm
public class AccountRealm extends AuthorizingRealm {
@Autowired
private AccountService accountService;
/**
* 登录认证 登录逻辑
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//获取浏览器token
UsernamePasswordToken token=(UsernamePasswordToken) authenticationToken;
String username = token.getUsername();
//查询数据库比对
Account account = accountService.findAccountByUsername(username);
if (account!=null){
//shiro封装判断密码
return new SimpleAuthenticationInfo(account,account.getPassword(),getName());
}
return null;
}
/**
* 登录后才能 授权判断
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//此时用户以及登录认账成功,从subject中获取用户对象
Subject subject= SecurityUtils.getSubject();
Account account = (Account) subject.getPrincipal();
//从数数据库中查询该用户拥有的 权限,角色信息
String perms = account.getPerms();
String role = account.getRole();
//角色用set集合保存
HashSet<String> roles = new HashSet<>();
roles.add(role);
//权限认证对象
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setRoles(roles);
info.addStringPermission(perms);
return info;
}
}
3、配置类
//配置后组件才能生效
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//设置页面权限
HashMap<String, String> map = new HashMap<>();
map.put("/main","authc");//设置main页面的登录认证权限
map.put("/manager","perms[manager]");//设置manager页面必须拥有manager权限才能访问
map.put("/administrator","roles[administrator]");//设置administrator页面必须有administrator角色才能访问
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
shiroFilterFactoryBean.setLoginUrl("/login");//跳转到自定义登录请求或页面
shiroFilterFactoryBean.setUnauthorizedUrl("Unauthorized");//登录但没有权限跳转的请求或页面
return shiroFilterFactoryBean;
}
@Bean
public DefaultWebSecurityManager securityManager(@Qualifier("accountRealm") AccountRealm accountRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(accountRealm);
return securityManager;
}
@Bean
public AccountRealm accountRealm(){
return new AccountRealm();
}
}
4、登录退出逻辑
@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) {
//将用户名密码 封装为token
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
//subject用来存储用户信息
Subject subject = SecurityUtils.getSubject();
try {
//执行的是我们在Realm中自定义的登录认证方法
subject.login(token);
//到此处说明 登录认证是成功的
Session session = subject.getSession();
Account account = (Account) subject.getPrincipal();
session.setAttribute("account",account);
return "index";
} catch (UnknownAccountException e) {
e.printStackTrace();
model.addAttribute("msg", "账号错误");
return "login";
} catch (IncorrectCredentialsException e) {
e.printStackTrace();
model.addAttribute("msg", "密码错误");
return "login";
}
}
@GetMapping("/logout")
public String logout(){
Subject subject=SecurityUtils.getSubject();
subject.logout();
return "login";
}
}
4、参数详情
编写认证和授权规则:
> 认证过滤器
anon:无需认证。
authc:必须登录才访问
authcBasic:需要通过 HTTPBasic 认证。
user:不一定通过认证,只要曾经被 Shiro 记录即可,比如:记住我。
> 授权过滤器
perms:必须拥有某个权限才能访问。
role:必须拥有某个角色才能访问。
port:请求的端口必须是指定值才可以。
rest:请求必须基于 RESTful,POST、PUT、GET、DELETE。
ssl:必须是安全的 URL 请求,协议 HTTPS。
5、根据权限动态展示资源页面
Shiro 整合 Thymeleaf
1、pom.xml 引入依赖
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
2、配置类添加 ShiroDialect
@Bean
public ShiroDialect shiroDialect(){
return new ShiroDialect();
}
3、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>