springboot整合shiro+jwt+redis实现权限校验,项目实战,有开源项目

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中查找用户及其权限信息。

项目地址

关注I am Walker 回复shiro即可

使用案例
1、新建表

主要有下列5个表,分别为:用户、角色、菜单、用户角色关联表、角色菜单关联表
是比较符合我们基本的业务需求的
image.png
然后这里提供测试的sql结构和数据



SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for sys_menu
-- ----------------------------
DROP TABLE IF EXISTS `sys_menu`;
CREATE TABLE `sys_menu`  (
  `id` int(0) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '名称',
  `path` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '路径',
  `perm` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '权限',
  `create_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '创建人',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '更新人',
  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '菜单' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_menu
-- ----------------------------
INSERT INTO `sys_menu` VALUES (1, '用户查询', NULL, 'user:list', NULL, NULL, NULL, NULL);
INSERT INTO `sys_menu` VALUES (2, '用户新增', NULL, 'user:add', NULL, NULL, NULL, NULL);

-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role`  (
  `id` int(0) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '唯一标识',
  `name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '名称',
  `create_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '创建人',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '更新人',
  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '角色表' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES (1, 'admin', '超级管理员', NULL, NULL, NULL, NULL);

-- ----------------------------
-- Table structure for sys_role_menu
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_menu`;
CREATE TABLE `sys_role_menu`  (
  `id` int(0) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `role_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '角色id',
  `menu_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '菜单id',
  `create_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '创建人',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '更新人',
  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '角色-菜单-关联表' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_role_menu
-- ----------------------------
INSERT INTO `sys_role_menu` VALUES (1, '1', '1', NULL, NULL, NULL, NULL);

-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user`  (
  `id` int(0) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '姓名',
  `username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户名',
  `password` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '密码',
  `create_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '创建人',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '更新人',
  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES (1, '超级', 'admin', 'e10adc3949ba59abbe56e057f20f883e', NULL, NULL, NULL, NULL);

-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role`  (
  `id` int(0) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `user_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户id',
  `role_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '角色id',
  `create_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '创建人',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '更新人',
  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户-角色关联表' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES (1, '1', '1', NULL, NULL, NULL, NULL);

SET FOREIGN_KEY_CHECKS = 1;

数据如下:
用户,admin,密码123456
角色:超级管理员 admin
菜单:user:list 用户查询
注:这里只是测试使用、如果是实际案例的话,超级管理员是拥有全部权限的

2、代码生成和mybatisplus整合

这里具体的可以查看该文章
生成对应的类controller、service、serviceImpl、mapper、mapper.xml等

3、编写AuthenticationToken实现类

这个目的主要是在Realm的认证和授权的时候,能够获取到token

package com.walker.shiro.common.config.shiro;

import lombok.AllArgsConstructor;
import org.apache.shiro.authc.AuthenticationToken;

/**
* author:walker
* time: 2023/2/10
* description:  AuthenticationToken的实现类
*/
@AllArgsConstructor
public class JwtToken implements AuthenticationToken {

    private String token;

    @Override
    public Object getPrincipal() {
        return token;
    }

    @Override
    public Object getCredentials() {
        return token;
    }
}

4、realm配置

该为主要用于配置认证和权限等

package com.walker.shiro.common.config.shiro;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.walker.shiro.common.utils.Assert;
import com.walker.shiro.common.utils.JWTUtils;
import com.walker.shiro.domain.model.SysMenu;
import com.walker.shiro.domain.model.SysRole;
import com.walker.shiro.domain.model.SysUser;
import lombok.extern.slf4j.Slf4j;
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.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.stream.Collectors;

/**
* author:walker
* time: 2023/2/10
* description:  token Realm 用于配置认证和权限等
*/
@Component
@Slf4j
//继承AuthorizingRealm
public class TokenRealm extends AuthorizingRealm {

    @Autowired
    private JWTUtils jwtUtils;


    /**
    * 生效条件,因为realm可以有很多个,所以需要进行设置
    */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }

    /**
    *  权限配置
    */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        String token = principalCollection.toString();
        Assert.isBlank(token,"token不存在,请先登录");

        SysUser userEntity = jwtUtils.parseToken(token, SysUser.class);
        Assert.isNull(userEntity,"token解析失败,请重新登录");
        log.info("登录用户信息:{}", JSON.toJSONString(userEntity));

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //设置角色
        List<SysRole> roles = userEntity.getRoles();
        Assert.isCollEmpty(roles,"该用户未绑定角色");

        authorizationInfo.addRoles(roles.stream().map(SysRole::getKey).collect(Collectors.toSet()));
        //设置权限
        for (SysRole role : roles) {
            List<SysMenu> menuEntityList = role.getMenus();
            if(CollUtil.isEmpty(menuEntityList)){
                continue;
            }
            authorizationInfo.addStringPermissions(menuEntityList.stream().map(SysMenu::getPerm).collect(Collectors.toSet()));
        }
        log.info("用户{} shiro角色:{} 权限:{}",userEntity.getUsername(),authorizationInfo.getRoles(),authorizationInfo.getStringPermissions());
        return authorizationInfo;
    }


    /**
    * 认证配置
    */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String token = (String) authenticationToken.getCredentials();
        return new SimpleAuthenticationInfo(token,token,getName());
    }
}

5、token过滤器
package com.walker.shiro.common.config.shiro;

import cn.hutool.core.util.StrUtil;
import com.walker.shiro.common.constants.RedisConstant;
import com.walker.shiro.common.properties.JWTProperties;
import com.walker.shiro.common.utils.HttpUtils;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.springframework.data.redis.core.StringRedisTemplate;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

/**
 * author:walker
 * time: 2023/2/10
 * description:  token过滤器
 */
public class TokenFilter extends BasicHttpAuthenticationFilter {

    /**
    * 这里因为TokenFilter不是容器,所以需要设置属性,然后通过初始化的时候传递
    */
    private StringRedisTemplate redisTemplate;

    private JWTProperties jwtProperties;

    public TokenFilter(StringRedisTemplate redisTemplate, JWTProperties jwtProperties) {
        this.redisTemplate = redisTemplate;
        this.jwtProperties = jwtProperties;
    }

    /**
    * isAccessAllowed:是否允许访问
    */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        if(isLoginAttempt(request, response)){
            try {
                executeLogin(request, response);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return true;
        }
        return false;
    }

    /**
     * onAccessDenied:拒绝访问时,需要做什么处理
     * 如果isAccessAllowed方法返回True,则不会再调用onAccessDenied方法,如果isAccessAllowed方法返回Flase,则会继续调用onAccessDenied方法。
     * 而onAccessDenied方法里面则是具体执行登陆的地方。由于我们已经登陆,所以此方法就会返回True(filter放行),所以上面的onPreHandle方法里面的onAccessDenied方法就不会被执行。
     *
    */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        //这里直接返回false,如果不支持访问时,直接为false即可
        return false;
    }


    /**
    * 尝试登录
    */
    @SneakyThrows
    @Override
    protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
        HttpServletRequest req= (HttpServletRequest) request;
        String token = req.getHeader(jwtProperties.getHeader());
        if(StrUtil.isEmpty(token)){
            HttpUtils.resp(response,"请先进行登录");
            return false;
        }
        //判断token是否存在,如果不存在则证明失效或者过期
        String s = redisTemplate.opsForValue().get(RedisConstant.TOKEN_USER_KEY + token);
        if(StrUtil.isEmpty(s)){
            HttpUtils.resp(response,"token已失效/不存在,请重新登录");
            return false;
        }
        return true;
    }


    /**
    *  执行登录
    */
    @Override
    protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest req= (HttpServletRequest) request;
        String token = req.getHeader(jwtProperties.getHeader());
        JwtToken jwtToken = new JwtToken(token);
        getSubject(request, response).login(jwtToken);
        return true;
    }


}

6、shiro配置
package com.walker.shiro.common.config.shiro;

import com.walker.shiro.common.properties.JWTProperties;
import com.walker.shiro.common.utils.JWTUtils;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;

import javax.servlet.Filter;
import java.util.HashMap;

/**
*  shiro配置
*/
@Configuration
public class ShiroConfig {

    @Autowired
    private TokenRealm tokenRealm;
    @Autowired
    private JWTProperties jwtProperties;
    @Autowired
    private StringRedisTemplate redisTemplate;

    //免校验
    String ANON="anon";

    //filter名称 token
    String FILTER_TOKEN="token";

    //所有路径
    String ALL_PATH="/**";

    /**
     * 过滤工厂
     * 配置哪些请求需要过滤器,哪些不需要
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(securityManager);

        //添加token过滤器
        HashMap<String, Filter> filterHashMap = new HashMap<>(1);
        filterHashMap.put(FILTER_TOKEN,new TokenFilter(redisTemplate,jwtProperties));
        bean.setFilters(filterHashMap);

        //请求过滤
        //需要认证:authc 不需要认证:anon
        //token: 需要经过token过滤器处理
        HashMap<String, String> map = new HashMap<>();
        //白名单
        String[] whiteList = jwtProperties.getWhiteList().split(",");
        for (String s : whiteList) {
            map.put(s,ANON);
        }
        map.put(ALL_PATH,FILTER_TOKEN);
        bean.setFilterChainDefinitionMap(map);
        return bean;
    }


    /**
     * 安全管理器
     * 设置realm和关闭session
     */
    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        //设置realm
        manager.setRealm(tokenRealm);

        //关闭shiro自带的session,现在使用jwt 不需要session
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator sessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        sessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(sessionStorageEvaluator);
        manager.setSubjectDAO(subjectDAO);
        return manager;
    }




    /**
     * 根据spring-framework-reference,DefaultAdvisorAutoProxyCreator创建代理更加通用强大,使用此机制包括:
     * a.指定一个DefaultAdvisorAutoProxyCreator Bean的定义.
     * b.指定在相同或相关的上下文中任意数量的Advisor.注意,必须是Advisor,而不仅仅是interceptor或advice.这是必要的,因为必须有一个切点被评估,以便检查每个advice到候选bean定义是否合格
     */
    /**
     * @ConditionalOnMissingBean,它是修饰bean的一个注解,主要实现的是,当你的bean被注册之后,如果而注册相同类型的bean,就不会成功,它会保证你的bean只有一个,即你的实例只有一个,当你注册多个相同的bean时,会出现异常
     */
    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
        proxyCreator.setProxyTargetClass(true);
        return proxyCreator;
    }

    /**
     * 授权属性源顾问
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

}

7、controller测试类
package com.walker.shiro.domain.controller;


import com.sun.media.sound.FFT;
import com.walker.shiro.domain.component.UserComponent;
import com.walker.shiro.domain.model.common.R;
import com.walker.shiro.domain.model.form.UserLoginForm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

/**
 * <p>
 * 用户表 前端控制器
 * </p>
 *
 * @author walker
 * @since 2023-02-09
 */
@RestController
@RequestMapping("/sys-user")
public class SysUserController {

    @Autowired
    private UserComponent userComponent;

    /**
    * 登录接口
    */
    @PostMapping("/login")
    public R login(@RequestBody @Valid UserLoginForm form){
        return R.ok(userComponent.login(form));
    }



    /**
    * 新增用户接口
    */
    @PostMapping("/add")
    public R add(@RequestBody @Valid UserLoginForm form){
        userComponent.add(form);
        return R.ok();
    }

}

package com.walker.shiro.domain.controller;

import com.walker.shiro.domain.model.common.R;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/test")
public class TestController {

    @GetMapping("/get")
    public R get(){
        return R.ok("hello");
    }

    @GetMapping("/role_admin")
    @RequiresRoles("admin")
    public R role_admin(){
        return R.ok("OK");
    }

    @GetMapping("/role_vip")
    //角色判断
    @RequiresRoles("vip")
    public R role_vip(){
        return R.ok("OK");
    }

    @GetMapping("/userAdd")
    @RequiresPermissions("user:add")
    public R userAdd(){
        return R.ok("fail");
    }

    @GetMapping("/userList")
    @RequiresPermissions("user:list")
    public R userList(){
        return R.ok("ok");
    }

}

8、使用postman进行测试
  • login接口

login接口因为是设置为白名单的,所以不需要Token,直接放行
可以发现能够获取到token,
image.png
之后将登录之后的token复制一下,用来其他接口的测试

  • get 接口,不带token时

image.png
可以发现,提示需要token

  • get接口, 带token

image.png
当带上token时,就ok了

  • role_admin接口

image.png
该接口需要admin这个角色,然后目前我们的admin账号刚好有该角色
image.png
发现是可以获取到结果的

  • role_vip接口

image.png
image.png
该接口需要vip角色,admin没有,所以结果提示为没有权限

  • userAdd接口

image.png
image.png
由于admin只有user:list账号,所以不具备该权限

  • userList

调用成功
image.png

总结

权限管理可以说在大部分的项目都是需要使用的了,shiro具体权限和认证的配置,是符合我们企业项目开发的,所以我们还是得学习一下,希望对你有所帮助哈

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring Boot是一个开源的Java框架,用于构建独立的、可执行的、生产级的Spring应用程序。它极大地简化了Spring应用程序的搭建和部署过程,提供了一整套开箱即用的特性和插件,极大地提高了开发效率。 Shiro是一个强大且灵活的开源Java安全框架,提供了身份验证、授权、加密和会话管理等功能,用于保护应用程序的安全。它采用插件化的设计,支持与Spring等常用框架的无缝集成,使开发者能够轻松地在应用程序中添加安全功能。 JWT(JSON Web Token)是一种用于在客户端和服务端之间传输安全信息的开放标准。它使用JSON格式对信息进行包装,并使用数字签名进行验证,确保信息的完整性和安全性。JWT具有无状态性、可扩展性和灵活性的特点,适用于多种应用场景,例如身份验证和授权。 Redis是一个开源的、高性能的、支持多种数据结构的内存数据库,同时也可以持久化到磁盘中。它主要用于缓存、消息队列、会话管理等场景,为应用程序提供高速、可靠的数据访问服务。Redis支持丰富的数据类型,并提供了强大的操作命令,使开发者能够灵活地处理各种数据需求。 综上所述,Spring Boot结合ShiroJWTRedis可以构建一个安全、高性能的Java应用程序。Shiro提供了强大的安全功能,包括身份验证和授权,保护应用程序的安全;JWT用于安全传输信息,确保信息的完整性和安全性;Redis作为缓存和持久化数据库,提供了高速、可靠的数据访问服务。通过使用这些技术,开发者能够快速、高效地构建出符合安全和性能需求的应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WalkerShen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值