springboot+shiro+jwt
1.添加依赖
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>io.fusionauth</groupId> <artifactId>fusionauth-jwt</artifactId> <version>3.0.0</version> </dependency>
2.生成公钥私钥
公钥私钥非必须
可以参考:
FusionAuth/fusionauth-jwt: A simple to use Java 8 JWT Library. Verify, Sign, Encode, Decode all day.
https://github.com/fusionauth/fusionauth-jwt
使用openssl,我本地的环境是在git bash里运行的.
openssl genrsa -out rsa_private_key.pem openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
将这两个文件复制到resources/keys/ 里.
3.主要的代码
3.1 jwt工具
AppConstant.java
public final class AppConstant { public static final String JWT_PRIVATE_KEY_PATH = "keys/rsa_private_key.pem"; public static final String JWT_PUBLIC_KEY_PATH = "keys/rsa_public_key.pem"; public static final String JWT_ISSUER = "www.demo.com"; public static final Integer JWT_Expiration = 60; }
JWTUtil.java
import io.fusionauth.jwt.Signer; import io.fusionauth.jwt.Verifier; import io.fusionauth.jwt.domain.JWT; import io.fusionauth.jwt.rsa.RSASigner; import io.fusionauth.jwt.rsa.RSAVerifier; import lombok.extern.slf4j.Slf4j; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.time.ZoneOffset; import java.time.ZonedDateTime; @Slf4j public class JWTUtil { /** * 生成jwt token. * * @param subject * @return */ public static String genJwt(String subject) { File pri = new File(JWTUtil.class.getClassLoader().getResource(AppConstant.JWT_PUBLIC_KEY_PATH).getPath()); byte[] bFile; try { bFile = Files.readAllBytes(pri.toPath()); } catch (IOException e) { throw new RuntimeException("检查私钥文件是否存在"); } Signer signer = RSASigner.newSHA256Signer(new String(bFile)); // 构建 JWT with an issuer(iss), issued at(iat), subject(sub) and expiration(exp) JWT jwt = new JWT().setIssuer(AppConstant.JWT_ISSUER) .setIssuedAt(ZonedDateTime.now(ZoneOffset.UTC)) .setSubject(subject) .setExpiration(ZonedDateTime.now(ZoneOffset.UTC).plusMinutes(AppConstant.JWT_Expiration)); // Sign and encode the JWT to a JSON string representation return JWT.getEncoder().encode(jwt, signer); } /** * 解析token. */ public static JWT parse(String encodedJWT) { File pub = new File(JWTUtil.class.getClassLoader().getResource(AppConstant.JWT_PRIVATE_KEY_PATH).getPath()); Verifier verifier = RSAVerifier.newVerifier(pub.toPath()); // Verify and decode the encoded string JWT to a rich object // * A JWT that is expired or not yet valid will not be decoded, instead a {@link JWTExpiredException} or {@link // * JWTUnavailableForProcessingException} exception will be thrown respectively. return JWT.getDecoder().decode(encodedJWT, verifier); } }
3.2 shiro配置
JWTAuthenticationToken.java
import com.example.boot.shirojwt.util.JWTUtil; import io.fusionauth.jwt.domain.JWT; import org.apache.shiro.authc.AuthenticationToken; public class JWTAuthenticationToken implements AuthenticationToken { private String token; public JWTAuthenticationToken(String token) { this.token = token; } @Override public JWT getPrincipal() { return JWTUtil.parse(token); } @Override public String getCredentials() { return token; } }
JWTTokenRealm.java
import io.fusionauth.jwt.JWTExpiredException; import io.fusionauth.jwt.JWTUnavailableForProcessingException; import lombok.extern.slf4j.Slf4j; 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.springframework.stereotype.Component; import java.util.HashSet; import java.util.Set; @Slf4j @Component public class JWTTokenRealm extends AuthorizingRealm { @Override public boolean supports(AuthenticationToken token) { return token instanceof JWTAuthenticationToken; } /** * 获取身份验证信息 * Shiro中,最终是通过 Realm 来获取应用程序中的用户、角色及权限信息的。 * * @param authenticationToken 用户身份信息 token * @return 返回封装了用户信息的 AuthenticationInfo 实例 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { final JWTAuthenticationToken jwtToken = (JWTAuthenticationToken) authenticationToken; try { String username = jwtToken.getPrincipal().subject; log.debug("[doGetAuthenticationInfo] username:{}", username); // 到数据库中查询用户; Object user /* = xxxDao.selectOne(username) */; if (user == null) { throw new AccountException("用户不存在"); } // 处理封号等等逻辑. }catch (JWTExpiredException e){ throw new AccountException("token过期"); }catch (JWTUnavailableForProcessingException e){ throw new AccountException("token解析失败"); }catch (RuntimeException e){ throw new AccountException("未知异常"); } return new SimpleAuthenticationInfo(jwtToken.getPrincipal(), jwtToken.getCredentials(), "JWTTokenRealm"); } /** * 获取授权信息. */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { // 配置用户的角色 权限 // principalCollection SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //获得该用户角色 Set<String> roleSet = new HashSet<>(); Set<String> permissionSet = new HashSet<>(); roleSet.add(""); permissionSet.add(""); info.setRoles(roleSet); info.setStringPermissions(permissionSet); return info; }}
JWTFilter.java
import org.apache.shiro.authz.UnauthorizedException; import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class JWTFilter extends BasicHttpAuthenticationFilter { @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws UnauthorizedException { executeLogin(request, response); return true; } /** * 执行登陆操作 */ @Override protected boolean executeLogin(ServletRequest request, ServletResponse response) { HttpServletRequest httpServletRequest = (HttpServletRequest) request; HttpServletResponse httpServletResponse = (HttpServletResponse) response; try { String token = httpServletRequest.getHeader("Authorization"); JWTAuthenticationToken jwtToken = new JWTAuthenticationToken(token); // 提交给realm进行登入,如果错误 抛出异常并在这里被捕获 getSubject(request, response).login(jwtToken); } catch (RuntimeException e) { try { // ! 此处的异常不会被全局异常处理捕获到. httpServletResponse.sendError(401, "token出错"); } catch (IOException e1) { } } return true; } }
ShiroConfig.java
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator; import org.apache.shiro.mgt.DefaultSubjectDAO; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.LifecycleBeanPostProcessor; 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.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.servlet.Filter; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; @Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean factory(SecurityManager securityManager) { ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean(); // 添加自己的过滤器并且取名为jwt Map<String, Filter> filterMap = new LinkedHashMap<>(); //设置我们自定义的JWT过滤器 filterMap.put("jwt", new JWTFilter()); factoryBean.setFilters(filterMap); factoryBean.setSecurityManager(securityManager); Map<String, String> filterRuleMap = new HashMap<>(); filterRuleMap.put("/user/login", "anon"); filterRuleMap.put("/**", "jwt"); factoryBean.setFilterChainDefinitionMap(filterRuleMap); return factoryBean; } @Bean public SecurityManager securityManager(JWTTokenRealm jwtTokenRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 设置自定义 realm. securityManager.setRealm(jwtTokenRealm); securityManager.setRememberMeManager(null); /* * 关闭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); securityManager.setSubjectDAO(subjectDAO); return securityManager; } /** * 添加注解. */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; } @Bean public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } }
3.3 调用
调用jwt工具类生成token (xxx) 返回前端, 前端通过在header中附加 Authorization: xxx
仅是一个大概的集成,其他的地方需要根据自己需要来补充.
springboot+shiro+jwt的更多相关文章
- Springboot shiro JWT集成总结
SpringBoot Shiro JWT 1.建表 DDL.sql CREATE TABLE `t_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, ` ...
- SpringBoot+Shiro+JWT前后端分离实现用户权限和接口权限控制
1. 引入需要的依赖 我使用的是原生jwt的依赖包,在maven仓库中有好多衍生的jwt依赖包,可自己在maven仓库中选择,实现大同小异. <dependency> <groupI ...
- 基于Shiro,JWT实现微信小程序登录完整例子
小程序官方流程图如下,官方地址 : https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html ...
- 基于shiro+jwt的真正rest url权限管理,前后端分离
代码地址如下:http://www.demodashi.com/demo/13277.html bootshiro & usthe bootshiro是基于springboot+shiro+j ...
- spring-boot-plus集成Shiro+JWT权限管理
SpringBoot+Shiro+JWT权限管理 Shiro Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理. 使用Shiro的易于理解的API,您可以 ...
- 教你 Shiro + SpringBoot 整合 JWT
本篇文章将教大家在 shiro + springBoot 的基础上整合 JWT (JSON Web Token) 如果对 shiro 如何整合 springBoot 还不了解的可以先去看我的上一篇文章 ...
- Shiro (Shiro + JWT + SpringBoot应用)
Shiro (Shiro + JWT + SpringBoot应用) 目录 Shiro (Shiro + JWT + SpringBoot应用) 1.Shiro的简介 2.Shiro + JWT + ...
- SpringBoot集成JWT 实现接口权限认证
JWT介绍 Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的, 特别适用于分布式站点 ...
- Shiro&Jwt验证
此篇基于 SpringBoot 整合 Shiro & Jwt 进行鉴权 相关代码编写与解析 首先我们创建 JwtFilter 类 继承自 BasicHttpAuthenticationFilt ...
随机推荐
- mysqlbinlog初识
mysql-binlog->解析mysql的binlog日志 mysql的binlog日志是什么? 数据目录下的日下文件就是mysql的binlog日志 mysql-bin.00001 mysq ...
- grub2 详解
grub2详解(翻译和整理官方手册) 分类: Linux 基础篇,Linux 杂项 本文原创地址在博客园:https://www.cnblogs.com/f-ck-need-u/archive ...
- Field 'id' doesn't have a default value 原因
Field 'id' doesn't have a default value昨晚做项目的时候遇到一个问题,在测试数据存储的时候老是报Field 'id' doesn't have a default ...
- VScode+Flutter 开发继续踩坑
运行慢解决方法1:修改build.gradle,注释掉jcenter(),google().使用阿里的镜像.原因是jcenter google库无法访问到导致的问题.虽然我有万能的爬墙工具,开启全局代 ...
- spring注解-@Autowired。@Resource。@Service
Spring的@Autowired注解.@Resource注解和@Service注解 什么是注解 传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop.事物,这么做有两个缺点: ...
- CF1056:Check Transcription(被hack的hash)
One of Arkady's friends works at a huge radio telescope. A few decades ago the telescope has sent a ...
- 【thrift】thrift详解
转载:http://zheming.wang/thrift-rpcxiang-jie.html Thrift Thrift是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年 ...
- 文件和I/O流
版权声明:本文为[博主](https://zhangkn.github.io)原创文章,未经博主同意不得转载.https://creativecommons.org/licenses/by-nc-sa ...
- cocos2dx 安卓真机调试问题汇总
cocos compile编译apk问题汇总: 1,dx编译报错,没有足够的空间 ANTBUILD : [dx] error : Could not create the Java Virtual M ...
- centos下安装docker最新版教程
1.通过yum安装需要root或者能sudo的权限 yum包更新到最新$ sudo yum update 添加Docker yum源$ sudo tee /etc/yum.repos.d/docker ...