Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
一、主要功能
三个核心组件:Subject, SecurityManager 和 Realms.
Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。
Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果系统默认的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。
基本功能点
特点
1、Shiro不依赖容器,创建maven工程 / springboot项目都可
2、添加shiro依赖
- <dependency>
- <groupId>org.apache.shirogroupId>
- <artifactId>shiro-coreartifactId>
- <version>1.4.1version>
- dependency>
Shiro 获取权限相关信息可以通过数据库获取,也可以通过 ini 配置文件获取
- [users]
- zhangsan=z3
- lisi=l4
创建测试类,获取认证对象,进行登录认证,如下:
- package com.syh.shiro.text;
-
- import org.apache.shiro.SecurityUtils;
- import org.apache.shiro.authc.*;
- import org.apache.shiro.config.IniSecurityManagerFactory;
- import org.apache.shiro.mgt.SecurityManager;
- import org.apache.shiro.subject.Subject;
-
- public class Role{
- public static void main(String[] args) {
- //1 初始化获取 SecurityManager
- IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:static/shiro.ini");
- SecurityManager securityManager = factory.getInstance();
- SecurityUtils.setSecurityManager(securityManager);
- //2 获取 Subject 对象
- Subject subject = SecurityUtils.getSubject();
- //3 创建 token 对象,web 应用用户名密码从页面传递
- AuthenticationToken token = new UsernamePasswordToken("zhangsan","z3");
- //4 完成登录
- try {
- subject.login(token);
- System.out.println("登录成功");
- }
- catch (UnknownAccountException e) {
- e.printStackTrace();
- System.out.println("用户不存在");
- }
- catch (IncorrectCredentialsException e) {
- e.printStackTrace();
- System.out.println("密码错误");
- }
- catch (AuthenticationException ae) {
- //unexpected condition? error?
- }
- }
- }
(1)编程式:通过写if/else 授权代码块完成
(2)注解式:通过在执行的Java方法上放置相应的注解完成,没有权限将抛出相 应的异 常
1、获取角色信息
(1)给shiro.ini增加角色配置
- [users]
- zhangsan=z3,role1,role2
- lisi=l4
(2)上述示例代码中添加代码,沟通过hasRole()判断用户是否有指定角色
- try {
- subject.login(token);
- System.out.println("登录成功");
-
- // 沟通过hasRole()判断用户是否有指定角色
- boolean role1 = subject.hasRole("role1");
- System.out.println("是否拥有此角色:" + role1);
- }
2、判断权限信息信息
(1)给shiro.ini增加权限配置
- [roles]
- role1=user:insert,user:select
(2)给例子添加代码,判断用户是否有指定权限
- //判断权限信息信息
- boolean isPermitted = subject.isPermitted("user:insert");
- System.out.println("是否拥有此权限:"+isPermitted);
- //也可以用 checkPermission 方法,但没有返回值,没权限抛 AuthenticationException
- subject.checkPermission("user:select");
实际系统开发中,一些敏感信息需要进行加密,比如说用户的密码。Shiro 内嵌很多 常用的加密算法,比如 MD5 加密。Shiro 可以很简单的使用信息加密。
- package com.syh.shiro.text;
-
- import org.apache.shiro.crypto.hash.Md5Hash;
- import org.apache.shiro.crypto.hash.SimpleHash;
-
- public class ShiroJM {
-
- public static void main(String[] args) {
- //密码明文
- String password = "z3";
- //使用 md5 加密
- Md5Hash md5Hash = new Md5Hash(password);
- System.out.println("md5 加密:"+md5Hash.toHex());
- //带盐的 md5 加密,盐就是在密码明文后拼接新字符串,然后再进行加密
- Md5Hash md5Hash2 = new Md5Hash(password,"salt");
- System.out.println("md5 带盐加密:"+md5Hash2.toHex());
- //为了保证安全,避免被破解还可以多次迭代加密,保证数据安全
- Md5Hash md5Hash3 = new Md5Hash(password,"salt",3);
- System.out.println("md5 带盐三次加密:"+md5Hash3.toHex());
- //使用父类实现加密
- SimpleHash simpleHash = new SimpleHash("MD5",password,"salt",3);
- System.out.println("父类带盐三次加密:"+simpleHash.toHex());
- }
- }
Shiro 默认的登录认证是不带加密的,如果想要实现加密认证需要自定义登录认证, 自定义 Realm。
(1)自定义登录认证
- package com.syh.shiro.text;
-
- import org.apache.shiro.authc.AuthenticationException;
- import org.apache.shiro.authc.AuthenticationInfo;
- import org.apache.shiro.authc.AuthenticationToken;
- import org.apache.shiro.authc.SimpleAuthenticationInfo;
- import org.apache.shiro.realm.AuthenticatingRealm;
- import org.apache.shiro.util.ByteSource;
- import org.springframework.stereotype.Component;
-
- @Component
- public class MyRealm extends AuthenticatingRealm {
- //自定义的登录认证方法,Shiro 的 login 方法底层会调用该类的认证方法完成登录认证
- //需要配置自定义的 realm 生效,在 ini 文件中配置,或 Springboot 中配置
- //该方法只是获取进行对比的信息,认证逻辑还是按照 Shiro 的底层认证逻辑完成认证
- protected AuthenticationInfo doGetAuthenticationInfo(
- AuthenticationToken authenticationToken) throws
- AuthenticationException {
- //1 获取身份信息
- String principal = authenticationToken.getPrincipal().toString();
- //2 获取凭证信息
- String password = new String((char[])
- authenticationToken.getCredentials());
- System.out.println("认证用户信息:"+principal+"---"+password);
- //3 获取数据库中存储的用户信息
- if(principal.equals("zhangsan")){
- //3.1 数据库存储的加盐迭代 3 次密码
- String pwdInfo = "7174f64b13022acd3c56e2781e098a5f";
- //3.2 创建封装了校验逻辑的对象,将要比较的数据给该对象
- AuthenticationInfo info = new SimpleAuthenticationInfo(
- authenticationToken.getPrincipal(),
- pwdInfo,
- ByteSource.Util.bytes("salt"),
- authenticationToken.getPrincipal().toString());
- return info;
- }
- return null;
- }
- }
(2)在shiro.ini中添加配置信息
配置信息中有些为自定义登录认证配置类的路径信息
- [main]
- md5CredentialsMatcher=org.apache.shiro.authc.credential.Md5CredentialsMatcher
- md5CredentialsMatcher.hashIterations=3
-
- myrealm=com.syh.shiro.text.MyRealm
- myrealm.credentialsMatcher=$md5CredentialsMatcher
- securityManager.realms=$myrealm
-
- [users]
- zhangsan=7174f64b13022acd3c56e2781e098a5f,role1,role2
- lisi=l4
- [roles]
- role1=user:insert,user:select
-
(3)启动登录认证示例
(1)添加依赖
- <dependencies>
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-webartifactId>
- dependency>
-
- <dependency>
- <groupId>com.baomidougroupId>
- <artifactId>mybatis-plus-boot-starterartifactId>
- <version>3.5.2version>
- dependency>
- <dependency>
- <groupId>mysqlgroupId>
- <artifactId>mysql-connector-javaartifactId>
- <scope>runtimescope>
- dependency>
- <dependency>
- <groupId>org.projectlombokgroupId>
- <artifactId>lombokartifactId>
- <optional>trueoptional>
- dependency>
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-testartifactId>
- <scope>testscope>
- dependency>
- <dependency>
- <groupId>org.apache.shirogroupId>
- <artifactId>shiro-springartifactId>
- <version>1.4.1version>
- dependency>
- dependencies>
(2)目录结构
访问数据库获取用户信息,实现登录认证.
(1)数据库
- SET NAMES utf8mb4;
- SET FOREIGN_KEY_CHECKS = 0;
-
- -- ----------------------------
- -- Table structure for user
- -- ----------------------------
- DROP TABLE IF EXISTS `user`;
- CREATE TABLE `user` (
- `id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '编号',
- `name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',
- `pwd` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码',
- `r_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色编号',
- PRIMARY KEY (`id`) USING BTREE
- ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;
-
- -- ----------------------------
- -- Records of user
- -- ----------------------------
- INSERT INTO `user` VALUES ('11', 'zhangsan', '7174f64b13022acd3c56e2781e098a5f', '1111');
-
- SET FOREIGN_KEY_CHECKS = 1;
(2)实体类
- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- @TableName("user")
- public class User {
-
- @TableId("id")
- private Integer id;
-
- @TableField("name")
- private String name;
-
- @TableField("pwd")
- private String pwd;
-
- @TableField("rid")
- private Integer rid;
- }
(3)service业务
- @Service
- public class UserServiceImpl implements UserService {
-
- @Autowired
- private UserMapper userMapper;
-
- /* 根据用户名称获取用户信息 */
- @Override
- public User getUserInfoByName(String name) {
- LambdaQueryWrapper
wrapper = new LambdaQueryWrapper<>(); - wrapper.eq(User::getName, name);
- return userMapper.selectOne(wrapper);
- }
- }
(4)自定义realm
- /*
- * 自定义认证授权方法
- * */
- @Component
- public class MyRealm extends AuthorizingRealm {
-
- @Autowired
- private UserService userService;
-
- //自定义授权方法
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
- return null;
- }
-
- //自定义登录认证方法
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
- //1 获取用户身份信息
- String name = token.getPrincipal().toString();
- //2 调用业务层获取用户信息(数据库中)
- User user = userService.getUserInfoByName(name);
- //3 判断并将数据完成封装
- if(user!=null){
- AuthenticationInfo info = new SimpleAuthenticationInfo(
- token.getPrincipal(),
- user.getPwd(),
- ByteSource.Util.bytes("salt"),
- token.getPrincipal().toString()
- );
- return info;
- }
- return null;
- }
- }
(5)编写配置类
- @Configuration
- public class ShiroConfig {
-
- @Autowired
- private MyRealm myRealm;
-
- //配置 SecurityManager
- @Bean
- public DefaultWebSecurityManager defaultWebSecurityManager(){
- //1 创建 defaultWebSecurityManager 对象
- DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
- //2 创建加密对象,并设置相关属性
- HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
- //2.1 采用 md5 加密
- matcher.setHashAlgorithmName("md5");
- //2.2 迭代加密次数
- matcher.setHashIterations(3);
- //3 将加密对象存储到 myRealm 中
- myRealm.setCredentialsMatcher(matcher);
- //4 将 myRealm 存入 defaultWebSecurityManager 对象
- defaultWebSecurityManager.setRealm(myRealm);
- //5 返回
- return defaultWebSecurityManager;
- }
-
-
- // 过滤器
- @Bean
- public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
- ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
- shiroFilter.setSecurityManager(securityManager);
- // 拦截配置
- Map
filter = new LinkedHashMap<>(); - // 登录接口放行
- filter.put("/api/UserController/userLogin", "anon");
- // 需要拦截的资源
- filter.put("/**", "authc");
- shiroFilter.setFilterChainDefinitionMap(filter);
- return shiroFilter;
- }
-
- /*
- * 以后会用到的几个:
- * anon 无需认证即可访问
- * logout 退出清除HTTPSession数据
- * authc 需要认证才可访问
- * user user是介于,anon和authc直之间的。
- * 换句话来说:而“/authenticated= user”
- * 表示访问该地址的用户是身份验证通过或RememberMe 登录的都可以。
- * */
-
- }
(6)实现登录接口
- @RestController
- @RequestMapping("/api/UserController")
- @Slf4j
- public class UserController {
- // http://localhost:8080/api/UserController/userLogin?name=zhangsan&pwd=z3
- @GetMapping("/userLogin")
- public String userLogin(String name, String pwd){
- //1 获取 Subject 对象
- Subject subject = SecurityUtils.getSubject();
- //2 封装请求数据到 token 对象中
- AuthenticationToken token = new UsernamePasswordToken(name, pwd);
- //3 调用 login 方法进行登录认证
- try {
- subject.login(token);
- return "登录成功";
- } catch (AuthenticationException e) {
- log.error("登录失败");
- return "登录失败";
- }
- }
-
- }
多Realm验证,有时候会存在多Realm,不同的角色会有不同的验证逻辑,这个时候会需要多Realm。Shiro 的 ModularRealmAuthenticator 会使用内部的 AuthenticationStrategy 组件判断认 证是成功还是失败。
AuthenticationStrategy 是一个无状态的组件,它在身份验证尝试中被询问 4 次(这 4 次交互所需的任何必要的状态将被作为方法参数):
认证策略的另外一项工作就是聚合所有 Realm 的结果信息封装至一个 AuthenticationInfo 实例中,并将此信息返回,以此作为 Subject 的身份信息。
Shiro 中定义了 3 种认证odularRealmAuthenticat策略的实现,Mor 内置的认证策略默认实现是 AtLeastOneSuccessfulStrategy 方式。可以通过配置修改策略。
AuthenticationStrategy class
|
描述
|
AtLeastOneSuccessfulStrategy
|
只要有一个(或更多)的
Realm
验证成功,那么认证将视为成功
|
FirstSuccessfulStrategy
|
第一个
Realm
验证成功,整体认证将视为成功,且后续
Realm
将被忽略
|
AllSuccessfulStrategy
|
所有
Realm
成功,认证才视为成功
|
标题2已经配置一个realm名字为MyRealm,下面继续创建Customer2Realm
- @Component
- public class Customer2Realm extends AuthorizingRealm {
-
- @Autowired
- private UserService userService;
-
- //授权
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
- return null;
- }
-
- //认证
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
- // userName
- String principal = (String) authenticationToken.getPrincipal();
- // password
- // String credentials = (String) authenticationToken.getCredentials();
- // 根据用户名获取用户信息
- User user = userService.getUserInfoByName("zhangsan1");
- if(user != null){
- System.out.println("app认证成功");
- return new SimpleAuthenticationInfo(user, user.getPwd(), ByteSource.Util.bytes("salt"), principal);
- }else{
- return null;
- }
- }
- }
配置 SecurityManager,添加Customer2Realm(新添加3、5、5.1步)
- // 认证授权方法一
- @Autowired
- private MyRealm myRealm;
-
- // 认证授权方法二
- @Autowired
- private Customer2Realm customer2Realm;
-
- @Bean
- public DefaultWebSecurityManager defaultWebSecurityManager() {
- //1 创建 defaultWebSecurityManager 对象
- DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
- //2 创建认证对象,并设置认证策略
- ModularRealmAuthenticator modularRealmAuthenticator = new ModularRealmAuthenticator();
- //3 只要有一个(或更多)的 Realm 验证成功,那么认证将视为成功 默认值
- modularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
- defaultWebSecurityManager.setAuthenticator(modularRealmAuthenticator);
-
- //3 创建加密对象,并设置相关属性
- HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
- //3.1 采用 md5 加密
- matcher.setHashAlgorithmName("md5");
- //3.2 迭代加密次数
- matcher.setHashIterations(3);
- //4 将加密对象存储到 myRealm 中
- myRealm.setCredentialsMatcher(matcher);
-
- //5 封装 myRealm 集合
- List
list = new ArrayList<>(); - list.add(myRealm);
- //5.1 封装customer2Realm
- list.add(customer2Realm);
-
- //6 将 myRealm 存入 defaultWebSecurityManager 对象
- defaultWebSecurityManager.setRealms(list);
- //6.5 设置 rememberMe(Shiro 提供了记住我(RememberMe)的功能)
- defaultWebSecurityManager.setRememberMeManager(rememberMeManager());
- //7 返回
- return defaultWebSecurityManager;
- }
Shiro 提供了记住我(RememberMe)的功能,比如访问一些网站时,关闭了浏览器, 下次再打开时还是能记住你是谁, 下次访问时无需再登录即可访问。
(1) 首先在登录页面选中 RememberMe 然后登录成功;如果是浏览器登录,一般会 把 RememberMe 的 Cookie 写到客户端并保存下来;
(2) 关闭浏览器再重新打开;会发现浏览器还是记住你的;
(3) 访问一般的网页服务器端,仍然知道你是谁,且能正常访问;
(4) 但是,如果我们访问电商平台时,如果要查看我的订单或进行支付时,此时还 是需要再进行身份认证的,以确保当前用户还是你。
(1)修改配置类 ShiroConfig,在defaultWebSecurityManager方法放的6步后面添加代码,并且添加两个方法;在shiroFilterFactoryBean方法中添加过滤条件
- @Configuration
- public class ShiroConfig {
-
- @Autowired
- private MyRealm myRealm;
-
- //配置 SecurityManager
- @Bean
- public DefaultWebSecurityManager defaultWebSecurityManager() {
- //1 创建 defaultWebSecurityManager 对象
- DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
- //2 创建认证对象,并设置认证策略
- ModularRealmAuthenticator modularRealmAuthenticator = new ModularRealmAuthenticator();
- modularRealmAuthenticator.setAuthenticationStrategy(new AllSuccessfulStrategy());
- defaultWebSecurityManager.setAuthenticator(modularRealmAuthenticator);
-
- //3 创建加密对象,并设置相关属性
- HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
- //3.1 采用 md5 加密
- matcher.setHashAlgorithmName("md5");
- //3.2 迭代加密次数
- matcher.setHashIterations(3);
- //4 将加密对象存储到 myRealm 中
- myRealm.setCredentialsMatcher(matcher);
-
- //5 封装 myRealm 集合
- List
list = new ArrayList<>(); - list.add(myRealm);
-
- //6 将 myRealm 存入 defaultWebSecurityManager 对象
- defaultWebSecurityManager.setRealms(list);
- //6.5 设置 rememberMe(Shiro 提供了记住我(RememberMe)的功能)
- defaultWebSecurityManager.setRememberMeManager(rememberMeManager());
- //7 返回
- return defaultWebSecurityManager;
- }
-
- //cookie 属性设置
- public SimpleCookie rememberMeCookie(){
- SimpleCookie cookie = new SimpleCookie("rememberMe");
- //设置跨域
- //cookie.setDomain(domain);
- cookie.setPath("/");
- cookie.setHttpOnly(true);
- cookie.setMaxAge(30*24*60*60);
- return cookie;
- }
-
- //创建 Shiro 的 cookie 管理对象
- public CookieRememberMeManager rememberMeManager(){
- CookieRememberMeManager cookieRememberMeManager = new
- CookieRememberMeManager();
- cookieRememberMeManager.setCookie(rememberMeCookie());
-
- cookieRememberMeManager.setCipherKey("1234567890987654".getBytes());
- return cookieRememberMeManager;
- }
-
- //配置 Shiro 内置过滤器拦截范围
- @Bean
- public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
- ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
- shiroFilter.setSecurityManager(securityManager);
- // 拦截配置
- Map
filter = new LinkedHashMap<>(); - // 登录接口放行
- //设置需要进行登录认证的拦截范围
- filter.put("/**", "authc");
- //添加存在用户的过滤器(rememberMe)
- filter.put("/**", "user");
- shiroFilter.setFilterChainDefinitionMap(filter);
- return shiroFilter;
- }
-
- }
(2)修改 controller,新增一个访问参数
- package com.syh.shiro.controller;
-
- import com.syh.shiro.Utils.JWT.JwtUtil;
- import com.syh.shiro.Utils.relevant.RespStaticEnum;
- import com.syh.shiro.Utils.relevant.ResultUtils;
- import lombok.extern.slf4j.Slf4j;
- import org.apache.shiro.SecurityUtils;
- import org.apache.shiro.authc.AuthenticationException;
- import org.apache.shiro.authc.AuthenticationToken;
- import org.apache.shiro.authc.UsernamePasswordToken;
- import org.apache.shiro.subject.Subject;
- import org.springframework.web.bind.annotation.*;
-
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpSession;
-
- @RestController
- @RequestMapping("/api/UserController")
- @Slf4j
- public class UserController {
- // http://localhost:8080/api/UserController/userLogin/true?name=zhangsan&pwd=z3
- @GetMapping("/userLogin/{rememberMe}")
- public ResultUtils userLogin(String name, String pwd, @PathVariable boolean rememberMe, HttpServletRequest request){
- //1 获取 Subject 对象
- Subject subject = SecurityUtils.getSubject();
- //2 封装请求数据到 token 对象中
- AuthenticationToken token = new UsernamePasswordToken(name, pwd, rememberMe);
- //3 调用 login 方法进行登录认证
- try {
- subject.login(token);
- String jwtToken = JwtUtil.getJwtToken(name, pwd);
- return ResultUtils.success(RespStaticEnum.LOGIN_SUCCESS, jwtToken);
- } catch (AuthenticationException e) {
- log.error("登录失败");
- return ResultUtils.fail(RespStaticEnum.LOGIN_ERROR);
- }
- }
-
- // http://localhost:8080/api/UserController/get
- /*
- * 测试接口
- * 清理好浏览器cookie,直接访问此方法,会被拦截;
- * 如果先访问登录接口,然后再访问此接口,就可以访问;
- * 此刻关闭浏览器,再打开,然后访问此接口,发现依旧可以访问,这表明浏览器记住了登陆者
- * */
- @GetMapping("/get")
- public String getStr(HttpSession session, HttpServletRequest request) {
- session.setAttribute("user", "rememberMe");
- return "ss";
- }
-
- }
过滤器中添加如下配置
- // 配置登出,请求该地址,shiro清除HTTPSession数据,实现退出登录。
- filter.put("/api/UserController/logout", "logout");
用户登录后,需要验证是否具有指定角色指定权限。Shiro也提供了方便的工具进行判断。这个工具就是Realm的doGetAuthorizationInfo方法进行判断。触发权限判断的有两种方式,这里使用在接口服务中通过注解@Requires****进行判断
通过给接口服务方法添加注解可以实现权限校验,可以加在控制器方法上,也可以加 在业务方法上,一般加在控制器方法上。常用注解如下:
- SET NAMES utf8mb4;
- SET FOREIGN_KEY_CHECKS = 0;
-
- -- ----------------------------
- -- Table structure for role
- -- ----------------------------
- DROP TABLE IF EXISTS `role`;
- CREATE TABLE `role` (
- `r_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '编号',
- `name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色名',
- `desc` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述',
- PRIMARY KEY (`r_id`) USING BTREE
- ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色表' ROW_FORMAT = Dynamic;
-
- -- ----------------------------
- -- Records of role
- -- ----------------------------
- INSERT INTO `role` VALUES ('1111', '管理员', '全部权限');
-
- SET FOREIGN_KEY_CHECKS = 1;
- @Getter
- @Setter
- @TableName("role")
- public class Role implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * 角色id
- */
- @TableId("r_id")
- private String rId;
-
- /**
- * 角色名
- */
- @TableField("name")
- private String name;
-
- /**
- * 描述
- */
- @TableField("desc")
- private String desc;
- }
注解生效需要一些配置,在ShiroConfig配置文件中添加如下代码
- /*
- * 如下两个配置可以使shiro的权限校验注解生效
- * */
- @Bean
- public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
- DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
- defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
- return defaultAdvisorAutoProxyCreator;
- }
- //AuthorizationAttributeSourceAdvisor 的作用是匹配所有类 匹配所有加认证注解的方法
- //具体看这篇博客:https://blog.csdn.net/wangjun5159/article/details/51889628
- @Bean
- public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Autowired DefaultWebSecurityManager securityManager) {
- AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
- authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
- return authorizationAttributeSourceAdvisor;
- }
- @Component
- public class MyRealm extends AuthorizingRealm {
-
- @Autowired
- private UserService userService;
-
- @Autowired
- private IRoleService roleService;
-
- //自定义授权方法
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
- //1 创建对象,存储当前登录的用户的权限和角色
- SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
- //2 获取用户身份信息
- String principal = principalCollection.getPrimaryPrincipal().toString();
- //3 获取用户对应的角色信息
- List
roleList = roleService.getRoleName(principal); - //4 存储角色
- info.addRoles(roleList);
- //5 返回
- return info;
- }
-
- //自定义登录认证方法
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
- //1 获取用户身份信息
- String name = token.getPrincipal().toString();
- //2 调用业务层获取用户信息(数据库中)
- User user = userService.getUserInfoByName(name);
- //3 判断并将数据完成封装
- if(user!=null){
- AuthenticationInfo info = new SimpleAuthenticationInfo(
- token.getPrincipal(),
- user.getPwd(),
- ByteSource.Util.bytes("salt"),
- token.getPrincipal().toString()
- );
- return info;
- }
- return null;
- }
- }
- /*
- * 角色授权验证接口
- * */
- // 1111:管理员角色
- @RequiresRoles("1111")
- @GetMapping("/userLoginRoles")
- public String userLoginRoles() {
- System.out.println("登录认证验证角色");
- return "验证角色成功";
- }
数据库中只有1111角色,没有1111222角色
- SET NAMES utf8mb4;
- SET FOREIGN_KEY_CHECKS = 0;
-
- -- ----------------------------
- -- Table structure for permissions
- -- ----------------------------
- DROP TABLE IF EXISTS `permissions`;
- CREATE TABLE `permissions` (
- `id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '编号',
- `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限名',
- `info` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限信息',
- `desc` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述',
- PRIMARY KEY (`id`) USING BTREE
- ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '权限表' ROW_FORMAT = Dynamic;
-
- -- ----------------------------
- -- Records of permissions
- -- ----------------------------
- INSERT INTO `permissions` VALUES ('111111111', 'user:delete', '删除用户', '删除用户信息');
- INSERT INTO `permissions` VALUES ('1111111222', 'user:select', '查询用户信息', '查询用户信息');
-
- SET FOREIGN_KEY_CHECKS = 1;
- SET NAMES utf8mb4;
- SET FOREIGN_KEY_CHECKS = 0;
-
- -- ----------------------------
- -- Table structure for role_ps
- -- ----------------------------
- DROP TABLE IF EXISTS `role_ps`;
- CREATE TABLE `role_ps` (
- `id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '编号',
- `rid` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色 id',
- `pid` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限 id',
- PRIMARY KEY (`id`) USING BTREE
- ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色权限映射表' ROW_FORMAT = Dynamic;
-
- -- ----------------------------
- -- Records of role_ps
- -- ----------------------------
- INSERT INTO `role_ps` VALUES ('sahksah', '1111', '111111111');
-
- SET FOREIGN_KEY_CHECKS = 1;
- @Getter
- @Setter
- @TableName("permissions")
- public class Permissions implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * 编号
- */
- @TableId("id")
- private String id;
-
- /**
- * 权限名
- */
- @TableField("name")
- private String name;
-
- /**
- * 权限信息
- */
- @TableField("info")
- private String info;
-
- /**
- * 描述
- */
- @TableField("desc")
- private String desc;
- }
- @Getter
- @Setter
- @TableName("role_ps")
- public class RolePs implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * 编号
- */
- @TableId("id")
- private String id;
-
- /**
- * 角色 id
- */
- @TableField("rid")
- private String rid;
-
- /**
- * 权限 id
- */
- @TableField("pid")
- private String pid;
- }
- /*
- * 自定义认证授权方法
- * */
- @Component
- public class MyRealm extends AuthorizingRealm {
-
- // 用户
- @Autowired
- private UserService userService;
-
- // 角色
- @Autowired
- private IRoleService roleService;
-
- // 角色对应的权限
- @Autowired
- private IRolePsService rolePsService;
-
- //自定义授权方法
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
- //1 创建对象,存储当前登录的用户的权限和角色
- SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
- //2 获取用户身份信息
- String principal = principalCollection.getPrimaryPrincipal().toString();
- //3 获取用户对应的角色信息
- List
roleList = roleService.getRoleName(principal); - //4 存储角色
- info.addRoles(roleList);
- //5 获取用户权限信息
- List
jurisdictionList = rolePsService.getRolejurisdiction(roleList); - //6 储存权限信息
- info.addStringPermissions(jurisdictionList);
- //7 返回
- return info;
- }
-
- //自定义登录认证方法
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
- //1 获取用户身份信息
- String name = token.getPrincipal().toString();
- //2 调用业务层获取用户信息(数据库中)
- User user = userService.getUserInfoByName(name);
- //3 判断并将数据完成封装
- if(user!=null){
- AuthenticationInfo info = new SimpleAuthenticationInfo(
- token.getPrincipal(),
- user.getPwd(),
- ByteSource.Util.bytes("salt"),
- token.getPrincipal().toString()
- );
- return info;
- }
- return null;
- }
- }
- /*
- * 角色的权限验证接口
- * */
- @RequiresPermissions("user:delete")
- @GetMapping("/userJurisdiction")
- public String userJurisdiction() {
- System.out.println("角色权限验证");
- return "角色权限验证成功";
- }
集成到springboot全局异常处理中
- /*
- * 全局异常处理类
- * */
- @ControllerAdvice
- @Slf4j
- public class GlobalExceptionHandler {
-
- /*
- * 全局异常捕获
- * */
- @ResponseBody
- @ExceptionHandler(value = Exception.class)
- public ResultUtils javaExceptionHandler(Exception ex){
- return ResultUtils.fail(RespStaticEnum.FAIL, ex.getMessage());
- }
-
- /*
- * shiro框架权限校验失败异常捕获
- * */
- @ResponseBody
- @ExceptionHandler(UnauthorizedException.class)
- public ResultUtils unauthorizedException(Exception ex){
- log.error("无权限:" + ex.getLocalizedMessage());
- return ResultUtils.fail(RespStaticEnum.FAIL);
- }
- @ResponseBody
- @ExceptionHandler(AuthorizationException.class)
- public ResultUtils authorizationException(Exception ex){
- log.error("权限认证失败:" + ex.getLocalizedMessage());
- return ResultUtils.fail(RespStaticEnum.FAIL);
- }
- }
springboot整合EhCache学习请移步(1条消息) EhCache缓存框架_SUN Y H的博客-CSDN博客
Shiro官方提供了shiro-ehcache,实现了整合EhCache作为Shiro的缓存工具。可以缓 存认证执行的Realm方法,减少对数据库的访问,提高认证效率
-
- <dependency>
- <groupId>org.apache.shirogroupId>
- <artifactId>shiro-ehcacheartifactId>
- <version>1.5.2version>
- dependency>
- <dependency>
- <groupId>commons-iogroupId>
- <artifactId>commons-ioartifactId>
- <version>2.7version>
- dependency>
在 resources 下添加配置文件 ehcache/ehcache-shiro.xml
- "1.0" encoding="UTF-8"?>
- <ehcache name="ehcache" updateCheck="false">
-
- <diskStore path="java.io.tmpdir"/>
-
- <defaultCache
- maxEntriesLocalHeap="1000"
- eternal="false"
- timeToIdleSeconds="3600"
- timeToLiveSeconds="3600"
- overflowToDisk="false">
- defaultCache>
-
- <cache name="loginRolePsCache"
- maxEntriesLocalHeap="2000"
- eternal="false"
- timeToIdleSeconds="600"
- timeToLiveSeconds="0"
- overflowToDisk="false"
- statistics="true"/>
- ehcache>
6.6步为新添加,其他为之前代码
- @Bean
- public DefaultWebSecurityManager defaultWebSecurityManager() {
- //1 创建 defaultWebSecurityManager 对象
- DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
- //2 创建认证对象,并设置认证策略
- ModularRealmAuthenticator modularRealmAuthenticator = new ModularRealmAuthenticator();
- //3 只要有一个(或更多)的 Realm 验证成功,那么认证将视为成功 默认值
- modularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
- defaultWebSecurityManager.setAuthenticator(modularRealmAuthenticator);
-
- //3 创建加密对象,并设置相关属性
- HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
- //3.1 采用 md5 加密
- matcher.setHashAlgorithmName("md5");
- //3.2 迭代加密次数
- matcher.setHashIterations(3);
- //4 将加密对象存储到 myRealm 中
- myRealm.setCredentialsMatcher(matcher);
-
- //5 封装 myRealm 集合
- List
list = new ArrayList<>(); - list.add(myRealm);
- //5.1 封装customer2Realm
- list.add(customer2Realm);
-
- //6 将 myRealm 存入 defaultWebSecurityManager 对象
- defaultWebSecurityManager.setRealms(list);
- //6.5 设置 rememberMe(Shiro 提供了记住我(RememberMe)的功能)
- defaultWebSecurityManager.setRememberMeManager(rememberMeManager());
- //6.6 设置缓存管理器
- defaultWebSecurityManager.setCacheManager(getEhCacheManager());
- //7 返回
- return defaultWebSecurityManager;
- }
-
- //缓存管理器
- public EhCacheManager getEhCacheManager(){
- EhCacheManager ehCacheManager = new EhCacheManager();
- InputStream is = null;
- try {
- is = ResourceUtils.getInputStreamForPath(
- "classpath:ehcache/ehcache-shiro.xml");
- } catch (IOException e) {
- e.printStackTrace();
- }
- CacheManager cacheManager = new CacheManager(is);
- ehCacheManager.setCacheManager(cacheManager);
- return ehCacheManager;
- }
此处不贴运行结果图了,打开sql日志打印。登录之后,访问权限验证接口,第一次会查询数据库打印sql语句,第二次访问会走缓存,看不到sql语句打印。
当某个用户的权限被更新,应该同步更新EhCache中缓存
会话管理器,负责创建和管理用户的会话(Session)生命周期,它能够在任何环境中 在本地管理用户会话,即使没有Web/Servlet/EJB容器,也一样可以保存会话。默认情况 下,Shiro会检测当前环境中现有的会话机制(比如Servlet容器)进行适配,如果没有(比如独立应用程序或者非Web环境),它将会使用内置的企业会话管理器来提供相应的会 话管理服务,其中还涉及一个名为SessionDAO的对象。SessionDAO负责Session的持久化操 作(CRUD),允许Session数据写入到后端持久化数据库。
SessionManager由SecurityManager管理。Shiro提供了三种实现
Shiro内置了很多默认的拦截器,比如身份验证、授权等相关的。默认拦截器可以参考org.apache.shiro.web.filter.mgt.DefaultFilter中的枚举拦截器:
注意:anon, authc, authcBasic, user 是第一组认证过滤器,perms, port, rest, roles, ssl 是第二组授权过滤器,要通过授权过滤器,就先要完成登陆认证操作(即先要完成认证才能前去寻找授权) 才能走第二组授权器(例如访问需要 roles 权限的 url,如果还没有登陆的话,会直接跳转到 shiroFilterFactoryBean.setLoginUrl(); 设置的 url
默认拦截器名 | 拦截器类 | 说明(括号里的表示默认值) |
身份验证相关的 | ||
authc | org.apache.shiro.web.filter.authc .FormAuthenticationFilter | 基于表单的拦截器;如“/**=authc”,如果没有登录会跳到相应的登录页面登录;主要属性:usernameParam:表单提交的用户名参数名( username); passwordParam:表单提交的密码参数名(password); rememberMeParam:表单提交的密码参数名(rememberMe); loginUrl:登录页面地址(/login.jsp);successUrl:登录成功后的默认重定向地址; failureKeyAttribute:登录失败后错误信息存储key(shiroLoginFailure); |
authcBasic | org.apache.shiro.web.filter.authc .BasicHttpAuthenticationFilter | Basic HTTP身份验证拦截器,主要属性: applicationName:弹出登录框显示的信息(application); |
logout | org.apache.shiro.web.filter.authc .LogoutFilter | 退出拦截器,主要属性:redirectUrl:退出成功后重定向的地址(/);示例“/logout=logout” |
user | org.apache.shiro.web.filter.authc .UserFilter | 用户拦截器,用户已经身份验证/记住我登录的都可;示例“/**=user” |
anon | org.apache.shiro.web.filter.authc .AnonymousFilter | 匿名拦截器,即不需要登录即可访问;一般用于静态资源过滤;示例“/static/**=anon” |
授权相关的 | ||
roles | org.apache.shiro.web.filter.authz .RolesAuthorizationFilter | 角色授权拦截器,验证用户是否拥有所有角色;主要属性: loginUrl:登录页面地址(/login.jsp);unauthorizedUrl:未授权后重定向的地址;示例“/admin/**=roles[admin]” |
perms | org.apache.shiro.web.filter.authz .PermissionsAuthorizationFilter | 权限授权拦截器,验证用户是否拥有所有权限;属性和roles一样;示例“/user/**=perms["user:create"]” |
port | org.apache.shiro.web.filter.authz .PortFilter | 端口拦截器,主要属性:port(80):可以通过的端口;示例“/test= port[80]”,如果用户访问该页面是非80,将自动将请求端口改为80并重定向到该80端口,其他路径/参数等都一样 |
rest | org.apache.shiro.web.filter.authz .HttpMethodPermissionFilter | rest风格拦截器,自动根据请求方法构建权限字符串(GET=read, POST=create,PUT=update,DELETE=delete,HEAD=read,TRACE=read,OPTIONS=read, MKCOL=create)构建权限字符串;示例“/users=rest[user]”,会自动拼出“user:read,user:create,user:update,user:delete”权限字符串进行权限匹配(所有都得匹配,isPermittedAll); |
ssl | org.apache.shiro.web.filter.authz .SslFilter | SSL拦截器,只有请求协议是https才能通过;否则自动跳转会https端口(443);其他和port拦截器一样; |
其他 | ||
noSessionCreation | org.apache.shiro.web.filter.session .NoSessionCreationFilter | 不创建会话拦截器,调用 subject.getSession(false)不会有什么问题,但是如果 subject.getSession(true)将抛出 DisabledSessionException异常; |
学习该模块时,看的其他博主的帖子。试验了一下无一成功。应该是理解有误,然后放弃网上的方法,按照自己的理解写了这篇自定义jwt拦截器。
(1)用到的jwt工具类
(3条消息) jjwt工具类_SUN Y H的博客-CSDN博客
(2)创建自定义拦截器,实现BasicHttpAuthenticationFilter
- import com.syh.shiro.Utils.JWT.JwtUtil;
- import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
- import org.springframework.http.HttpStatus;
- import org.springframework.web.bind.annotation.RequestMethod;
-
- import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
-
- /**
- * @author ojj
- * @title: JwtFilter
- * @projectName test
- * @description: 拦截器
- * @date 2022/1/6 14:57
- */
- public class JwtFilter extends BasicHttpAuthenticationFilter {
-
- /**
- * 拦截器的前置 最先执行的 这里只做了一个跨域设置
- */
- @Override
- protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
- HttpServletRequest req = (HttpServletRequest) request;
- HttpServletResponse res = (HttpServletResponse) response;
- res.setHeader("Access-control-Allow-Origin", req.getHeader("Origin"));
- res.setHeader("Access-control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
- res.setHeader("Access-control-Allow-Headers", req.getHeader("Access-Control-Request-Headers"));
- // 跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态
- if (req.getMethod().equals(RequestMethod.OPTIONS.name())) {
- res.setStatus(HttpStatus.OK.value());
- return false;
- }
- return super.preHandle(request, response);
- }
-
- /**
- * preHandle 执行完之后会执行这个方法
- * 再这个方法中 我们根据条件判断去去执行isLoginAttempt和executeLogin方法
- */
- @Override
- protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
- /**
- * 先去调用 isLoginAttempt方法 字面意思就是是否尝试登陆 如果为true
- * 执行executeLogin方法
- */
- if (isLoginAttempt(request, response)) {
- executeLogin(request, response);
- return true;
- }
-
- return false;
- }
-
-
- /**
- * 这里我们只是简单去做一个判断请求头中的token信息是否为空
- * 如果没有我们想要的请求头信息则直接返回false
- */
- @Override
- protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
- HttpServletRequest req = (HttpServletRequest) request;
- String token = req.getHeader("X-Token");
- return token != null;
- }
-
- /**
- * 执行登陆
- * 因为已经判断token不为空了,所以直接执行登陆逻辑
- * 将token放入JwtToken类中去
- * 然后getSubject方法是调用到了MyRealm的 执行方法 因为上面我是抛错的所有最后做个异常捕获就好了
- */
- @Override
- protected boolean executeLogin(ServletRequest request, ServletResponse response) {
- HttpServletRequest req = (HttpServletRequest) request;
- String jwtToken = req.getHeader("X-Token");
- // 校验token是否有效
- if (JwtUtil.checkToken(jwtToken)) {
- return true;
- } else {
- return false;
- }
- }
-
-
- }
(3)ShiroConfig类中引入自定义jwt拦截器,并配置拦截路径
- //配置 Shiro 内置过滤器拦截范围
- @Bean
- public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
- ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
- shiroFilterFactoryBean.setSecurityManager(securityManager);
- // 拦截配置
- Map
filterMap = new LinkedHashMap<>(); - //引入自定义拦截器,命名为jwt
- filterMap.put("jwt", new JwtFilter());
- shiroFilterFactoryBean.setFilters(filterMap);
-
- Map
filterRuleMap=new LinkedHashMap<>(); - // 登录接口放行
- filterRuleMap.put("/api/UserController/userLogin/**", "anon");
- // 配置登出,请求该地址,shiro去清除session,实现退出登录。
- filterRuleMap.put("/api/UserController/logout", "logout");
- // 配置自定义jwt认证
- filterRuleMap.put("/api/UserController/jwtLan", "jwt");
- // 设置需要进行登录认证的拦截范围
- filterRuleMap.put("/**", "authc");
- // 添加存在用户的过滤器(rememberMe)
- filterRuleMap.put("/**", "user");
- shiroFilterFactoryBean.setFilterChainDefinitionMap(filterRuleMap);
- return shiroFilterFactoryBean;
- }
(4)登录接口将生成的token返回给前端
- //配置 Shiro 内置过滤器拦截范围
- @Bean
- public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
- ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
- shiroFilterFactoryBean.setSecurityManager(securityManager);
- // 拦截配置
- Map
filterMap = new LinkedHashMap<>(); - //引入自定义拦截器,命名为jwt
- filterMap.put("jwt", new JwtFilter());
- shiroFilterFactoryBean.setFilters(filterMap);
-
- Map
filterRuleMap=new LinkedHashMap<>(); - // 登录接口放行
- filterRuleMap.put("/api/UserController/userLogin/**", "anon");
- // 配置登出,请求该地址,shiro去清除session,实现退出登录。
- filterRuleMap.put("/api/UserController/logout", "logout");
- // 配置自定义jwt认证
- filterRuleMap.put("/api/UserController/jwtLan", "jwt");
- // 设置需要进行登录认证的拦截范围
- filterRuleMap.put("/**", "authc");
- // 添加存在用户的过滤器(rememberMe)
- filterRuleMap.put("/**", "user");
- shiroFilterFactoryBean.setFilterChainDefinitionMap(filterRuleMap);
- return shiroFilterFactoryBean;
- }
(5)测试,该访问路径会经过自定义jwt拦截器
- /*
- * 自定义jwt认证
- * */
- @GetMapping("/jwtLan")
- public String jwtLan() {
- System.out.println("自定义jwt认证");
- return "自定义jwt认证";
- }