创建 3 个页面,main.html、manage.html、administrator.html
访问权限如下:
1、必须登录才能访问 main.html 2、当前用户必须拥有 manage 授权才能访问 manage.html 3、当前用户必须拥有 administrator 角色才能访问 administrator.html
1、创建 Spring Boot 应用,集成 Shiro 及相关组件,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.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- springboot 整合Shiro权限框架 -->
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.7.1</version>
</dependency>
<!-- 数据库 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1.tmp</version>
</dependency>
<!-- shiro整合thymeleaf -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2、自定义 Shiro 过滤器
package com.gmw.realm;
import com.gmw.entity.Account;
import com.gmw.service.AccountService;
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;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashSet;
import java.util.Set;
public class AccountRealm extends AuthorizingRealm {
@Autowired
private AccountService accountService;
/**
* 认证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//UsernamePasswordToken封装了用户的所有的信息
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
//获取用户输入的用户名
String username = token.getUsername();
//调用service方法,实现根据用户名查询用户的对象
Account account = accountService.findByUsername(username);
//判断用户是否存在
if(account != null){
/**
* 参数1 表示通过用户名查询的用户对象
* 参数2 表示查询到用户对象的密码
* 参数3 getName()表示当前对象的本身
*
* 通过用户查询到的对象密码,和token中传入过来的密码做比较
*/
return new SimpleAuthenticationInfo(account,account.getPassword(),super.getName());
}
return null;
}
/**
* 授权
* @param principalCollection
* @return
*/
@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 simpleAuthorizationInfo = new SimpleAuthorizationInfo(roles);
//设置权限
simpleAuthorizationInfo.addStringPermission(account.getPerms());
return simpleAuthorizationInfo;
}
}
3、配置类
package com.gmw.config;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.gmw.realm.AccountRealm;
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.HashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
/**
* 需要将ShiroFilterFactoryBean过滤器工厂放到IOC的容器中,然后,将安全管理器注入到过滤器工厂中
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
//权限的设置
Map<String,String> map = new HashMap<>();
//用户访问main页面的时候,必须要登录认证
map.put("/main","authc");
//用户访问manage页面的时候,必须要有manage权限
map.put("/manage","perms[manage]");
//用户访问administrator页面的时候,必须要有administrator角色
map.put("/administrator","roles[administrator]");
//通过map初始化过滤器,创建三个过滤器对象
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
//设置登录的页面
shiroFilterFactoryBean.setLoginUrl("/login");
//设置为授权的页面
shiroFilterFactoryBean.setUnauthorizedUrl("/unauth");
return shiroFilterFactoryBean;
}
/**
* 需要将DefaultWebSecurityManager安全管理器注入到IOC的容器中,
* 并且,将开发者自定义的Realm注入到DefaultWebSecurityManager进行管理,才会生效
* @return
*/
@Bean
public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("accountRealm") AccountRealm accountRealm){
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
defaultWebSecurityManager.setRealm(accountRealm);
return defaultWebSecurityManager;
}
/**
* 需要将自定义的realm放到spring的容器中
* @return
*/
@Bean
public AccountRealm accountRealm(){
return new AccountRealm();
}
/**
* 自定义thymeleaf的shiro方言
* @return
*/
@Bean
public ShiroDialect shiroDialect(){
return new ShiroDialect();
}
}
编写认证和授权规则:
**
认证过滤器
anon:无需认证。
authc:必须认证。
authcBasic:需要通过 HTTPBasic 认证。
user:不一定通过认证,只要曾经被 Shiro 记录即可,比如:记住我。
授权过滤器
perms:必须拥有某个权限才能访问。
role:必须拥有某个角色才能访问。
port:请求的端口必须是指定值才可以。
rest:请求必须基于 RESTful,POST、PUT、GET、DELETE。
ssl:必须是安全的 URL 请求,协议 HTTPS。
4、编写Serivce方法根据用户名查询用户对象
@Service
public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements AccountService {
@Override
public Account findByUsername(String username) {
QueryWrapper wrapper = new QueryWrapper();
wrapper.eq("username",username);
return baseMapper.selectOne(wrapper);
}
}
5、编写Controller
package com.gmw.controller;
import com.gmw.entity.Account;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class AccountController {
/**
* 路径页面的跳转
* @param url
* @return
*/
@GetMapping(value = "/{url}")
public String redirect(@PathVariable("url") String url){
return url;
}
/**
* 用户登录操作
* @param username
* @param password
* @param model
* @return
*/
@PostMapping("/login")
public String login(String username, String password, Model model){
//获取主体对象
Subject subject = SecurityUtils.getSubject();
//创建UsernamePasswordToken对象,用来封装用户的登录信息
AuthenticationToken token = new UsernamePasswordToken(username,password);
try {
//登录
subject.login(token);
//登录成功后,从subject中获取Account对象
Account account = (Account) subject.getPrincipal();
//将登录的用户名称保存到session中
subject.getSession().setAttribute("username",account.getUsername());
//返回到index页面
return "index";
} catch (UnknownAccountException e) {
e.printStackTrace();
model.addAttribute("msg","用户名错误!");
return "login";
} catch (IncorrectCredentialsException e){
e.printStackTrace();
model.addAttribute("msg","密码错误!");
return "login";
}
}
/**
* 设置未授权的方法
* @return
*/
@GetMapping(value = "/unauth")
@ResponseBody
public String unauth(){
return "未授权, 无法访问!";
}
/**
* 退出
* @return
*/
@GetMapping(value = "/logout")
public String logout(){
Subject subject = SecurityUtils.getSubject();
subject.logout();
return "login";
}
}
6、编写html代码
index.html ```html <!DOCTYPE html>
index
main
- login.html
```html
<!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>
<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 colspan="2">
<input type="submit" value="登录"/>
</td>
</tr>
</table>
</form>
<br/>
<span th:text="${msg}" style="color: red;"></span>
</body>
</html>
main.html
<!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>main</h1> </body> </html>
manage.html
<!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>manage</h1> </body> </html>
admininstrator.html
<!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>administrator</h1> </body> </html>
7、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>