Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >SpringBoot集成Shiro权限+Jwt认证

SpringBoot集成Shiro权限+Jwt认证

作者头像
科技新语
发布于 2025-01-15 09:28:09
发布于 2025-01-15 09:28:09
14600
代码可运行
举报
运行总次数:0
代码可运行

背景

  • 为什么要使用Shiro

随大流吧,虽然自己也可以基于自定义注解+拦截器实现和Shiro一样的功能,但是为了适用于业界的规范,所以集成这个大家都能看得懂,而且Shiro也相对简单。

  • 为什么要用Jwt

传统的session模式越来越少,而且大多数系统都是微服务多客户端的,所以无状态的登陆更符合现阶段的业务架构。

开始

本案例基于SpringBoot 2.5.X + Shiro 1.8 + hutool的Jwt

pom.xml
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
xml 代码解读复制代码    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.5.4</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
            <version>2.5.4</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.24</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-web-starter</artifactId>
            <version>1.8.0</version>
        </dependency>
    </dependencies>
ResponseMessage返回消息体
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typescript 代码解读复制代码@Data
public class ResponseMessage<T> {

    private Boolean success = Boolean.TRUE;

    private String code;

    private String message;

    private T data;

    public static <T> ResponseMessage<T> success(T data){
        ResponseMessage<T> responseMessage = new ResponseMessage<>();
        responseMessage.setCode("200");
        responseMessage.setMessage("操作成功");
        responseMessage.setData(data);
        return responseMessage;
    }

    public static <T> ResponseMessage<T> fail(String message){
        ResponseMessage<T> responseMessage = new ResponseMessage<>();
        responseMessage.setSuccess(Boolean.FALSE);
        responseMessage.setCode("500");
        responseMessage.setMessage(message);
        return responseMessage;
    }

}
GlobalExceptionHandler全局异常处理
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
less 代码解读复制代码@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ResponseMessage<String> handleAllExceptions(Exception ex, WebRequest request) {
        // 处理异常
        log.error("业务异常",ex);
        return ResponseMessage.fail(ex.getMessage());
    }

}
JwtUtils工具类
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typescript 代码解读复制代码public class JwtUtils {

    private static final byte[] KEY = "ABADEXU".getBytes();

    public static String createToken(Map<String, Object> payload){
        return JWTUtil.createToken(payload, JwtUtils.KEY);
    }

    public static JWT parseToken(String token){
        return JWTUtil.parseToken(token);
    }

    public static Boolean verify(String token){
        return JWTUtil.verify(token, JwtUtils.KEY);
    }
}
JwtToken 认证dto
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typescript 代码解读复制代码@Data
public class JwtToken implements AuthenticationToken {

    /** JWT 认证串 */
    private String jwt;

    public JwtToken(String jwt) {
        this.jwt = jwt;
    }

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

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

}
JwtFilter 权限认证过滤器

拦截请求接口的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
scala 代码解读复制代码@Slf4j
public class JwtFilter extends AccessControlFilter {


    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        HttpServletRequest httpServletRequest   = (HttpServletRequest) request;
        String jwt                              = httpServletRequest.getHeader("Authorization");
        if(StrUtil.isNotBlank(jwt)){
            getSubject(request, response).login(new JwtToken(jwt));
            return true;
        }
        return false;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        throw new RuntimeException("身份验证异常");
    }

}
JwtRealm 授权领域

授权流程JwtFilter#isAccessAllowed -> JwtRealm#supports -> JwtRealm#doGetAuthenticationInfo -> JwtRealm#doGetAuthorizationInfo

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
java 代码解读复制代码@Slf4j
public class JwtRealm extends AuthorizingRealm {

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        log.info("验证jwt token 权限");
        String jwt = principalCollection.getPrimaryPrincipal().toString();
        // 这里一般就从redis中拿用户的权限信息,案例就直接写死了
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        // 设置角色
        simpleAuthorizationInfo.addRole("admin");
        simpleAuthorizationInfo.addRole("user");
        // 设置权限
        simpleAuthorizationInfo.addStringPermission("user:add");
        return simpleAuthorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        log.info("验证jwt token 有效性");
        String jwt = authenticationToken.getPrincipal().toString();
        // 从redis查询jwt token是否还存在,是否有效
        if(!Boolean.TRUE.equals(JwtUtils.verify(jwt))){
            throw new RuntimeException("jwt token 失效");
        }
        JWT parseToken = JwtUtils.parseToken(jwt);
        Object expiryTime = parseToken.getPayload("expiryTime");
        // 验证token是否过期
        return new SimpleAuthenticationInfo(jwt, jwt, this.getClass().getName());
    }
}
ShiroConfig 配置
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typescript 代码解读复制代码@Configuration
public class ShiroConfig {

    @Bean
    public JwtRealm jwtRealm(){
        return new JwtRealm();
    }

    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager() {
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(jwtRealm());
        /*
         * 关闭shiro自带的session,详情见文档
         * http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
         */
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        defaultWebSecurityManager.setSubjectDAO(subjectDAO);
        return defaultWebSecurityManager;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(defaultWebSecurityManager());
        // 未授权跳转
        shiroFilter.setUnauthorizedUrl("/unauthorized");
        Map<String, Filter> filterMap = new HashMap<>();
        //
        filterMap.put("jwt", new JwtFilter());
        //
        shiroFilter.setFilters(filterMap);

        Map<String, String> filterRuleMap = new LinkedHashMap<>();
        // 匿名访问
        filterRuleMap.put("/error", "anon");
        filterRuleMap.put("/login", "anon");
        filterRuleMap.put("/logout", "anon");
        filterRuleMap.put("/unauthorized", "anon");
        // 登录并具有 admin 角色
        // filterRuleMap.put("/index/admin", "authc,roles[admin]");
        // filterRuleMap.put("/index/admin", "jwt,roles[admin]");
        // 通过jwt校验,需登录才能访问(自行实现逻辑)
        filterRuleMap.put("/**", "jwt");
        //
        shiroFilter.setFilterChainDefinitionMap(filterRuleMap);
        //
        return shiroFilter;
    }

    /**
     * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions)
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setUsePrefix(true);
        return advisorAutoProxyCreator;
    }

}
测试相关
LoginController 登陆接口
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typescript 代码解读复制代码@RestController
public class LoginController {

    @GetMapping("login")
    public Object login(String username){
        Map<String, Object> payload = new HashMap<>();
        payload.put("username", username);
        // 设置30分钟后过期
        payload.put("expiryTime", DateUtil.date().offset(DateField.MINUTE, 30));
        return JwtUtils.createToken(payload);
    }

}
UserController 权限验证接口
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
less 代码解读复制代码@Slf4j
@RestController
@RequestMapping(value = "user")
public class UserController {

    @RequiresPermissions(value = {"user:view"})
    @GetMapping(value = "page")
    public Object page(){
        log.info("page");
        return "SUCCESS";
    }

    @RequiresPermissions(value = {"user:add"})
    @GetMapping(value = "add")
    public Object add(){
        log.info("add");
        return "SUCCESS";
    }

}

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【Java专题_01】springboot+Shiro+Jwt整合方案
Apache Shiro :是一个强大且易用的Java安全框架,执行身份认证,授权,密码和会话管理,核心组件:Subject,SecurityManager和Realms;
夏之以寒
2024/03/04
7990
【Java专题_01】springboot+Shiro+Jwt整合方案
从零开始做网站7-整合shiro+jwt实现用户认证和授权
上一篇用shiro来登入存在用户认证的问题,而又不想用cookie session,所以决定使用jwt来做用户认证
sunonzj
2022/06/21
1.2K0
从零开始做网站7-整合shiro+jwt实现用户认证和授权
第三节,SpringBoot集成shrio,Redis缓存session与权限
https://gitee.com/DencyCheng/springboot-shrio/tree/dev/
DencyCheng
2018/12/12
2.7K0
集成 SpringBoot 2.3.2 + Shiro 1.5.3 + jwt (无状态)
shiro 集成 jwt 需要禁用 session, 服务器就不用维护用户的状态, 做到无状态调用
北漂的我
2020/08/17
1.5K0
Shiro + JWT + Spring Boot Restful 简易教程
GitHub 项目地址:https://github.com/Smith-Cruise/Spring-Boot-Shiro 。
java思维导图
2020/04/22
9440
SpringBoot2.x集成Apache Shiro并完成简单的Case开发
在上文 Apache Shiro权限框架理论介绍 中,我们介绍了Apache Shiro的基础理论知识。本文我们将在 SpringBoot 中集成Apache Shiro,完成一些简单的Case开发。
端碗吹水
2020/09/23
6340
SpringBoot2.x集成Apache Shiro并完成简单的Case开发
一起来学SpringBoot | 第二十六篇:轻松搞定安全框架(Shiro)
Shiro是Apache 旗下开源的一款强大且易用的Java安全框架,身份验证、授权、加密、会话管理。 相比 SpringSecurity 而言 Shiro 更加轻量级,且 API 更易于理解...
battcn
2018/08/03
1.6K0
一起来学SpringBoot | 第二十六篇:轻松搞定安全框架(Shiro)
Shiro + JWT + Spring Boot Restful 简易教程
github.com/Smith-Cruise/Spring-Boot-Shiro
好好学java
2021/04/30
1.1K0
springboot整合shiro实现认证​
3.创建JwtDefaultSubjectFactory,来实现不保存session
java后端指南
2021/05/13
7610
springboot整合shiro实现认证​
实际项目教学:身份/权限验证
前几天给大家讲解了一下shiro,后台一些小伙伴跑来给我留言说:“一般不都是shiro结合jwt做身份和权限验证吗?能不能再讲解一下jwt的用法呢?“今天阿Q就给大家讲一下shiro整合jwt做权限校验吧。
阿Q说代码
2021/05/13
5990
实际项目教学:身份/权限验证
Springboot集成Shiro(前后端分离)
shiro是apache的一个开源框架,是一个权限管理的框架,实现 用户认证、用户授权。
Ant丶
2022/03/01
3.5K0
Springboot集成Shiro(前后端分离)
Springboot整合shiro框架
4. 编写前端页面 在templates目录下编写 login.html,add.html,delete.html,index.html 导入thymeleaf的dtd
JokerDJ
2023/11/27
3650
Springboot整合shiro框架
Spring Boot + Spring Cloud 实现权限管理系统 后端篇(十一):集成 Shiro 框架
Authentication(认证), Authorization(授权), Session Management(会话管理), Cryptography(加密)被 Shiro 框架的开发团队称之为应用安全的四大基石。
朝雨忆轻尘
2019/06/18
1.6K0
shiro、jwt、redis整合
HTTP协议(1.1)是无状态的,所以服务器在需要识别用户访问的时候,就要做相应的记录用于跟踪用户操作,这个实现机制就是Session。当一个用户第一次访问服务器的时候,服务器就会为用户创建一个Session,每个Session都有一个唯一的SessionId(应用级别)用于标识用户。
全栈程序员站长
2022/07/09
6090
Shiro简介及SpringBoot集成Shiro(狂神说视频简易版)
Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境,也可以用在JavaEE环
刘大猫
2025/06/01
1100
Shiro关闭session,无状态接入Springboot
本文基于token进行身份认证,由于接入cas会和shiro的session管理冲突,所以关闭shiro的session,进行无状态管理。
taixingyiji
2022/07/25
1.1K0
Shiro关闭session,无状态接入Springboot
使用Shiro实现认证和授权(基于SpringBoot)
Apache Shiro是一个功能强大且易于使用的Java安全框架,它为开发人员提供了一种直观,全面的身份验证,授权,加密和会话管理解决方案。下面是在SpringBoot中使用Shiro进行认证和授权的例子,代码如下:
布禾
2020/10/29
8510
Springboot整合Shiro之认证
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
用户4919348
2019/12/02
5120
Springboot整合Shiro之认证
基于Shiro,JWT实现微信小程序登录完整例子
小程序官方流程图如下,官方地址 : https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html :
EalenXie
2020/09/21
1.9K0
基于Shiro,JWT实现微信小程序登录完整例子
快速搭建Spring Boot项目及常用技术整合
Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。
一觉睡到小时候
2019/12/13
9720
推荐阅读
相关推荐
【Java专题_01】springboot+Shiro+Jwt整合方案
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验