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 ...
随机推荐
- bzoj2759
题解: lct+解线性方程组 首先先把每一个环搞出来,然后再建立一个额外的点 然后解方程.. 代码: #include <bits/stdc++.h> using namespace st ...
- Codeforces 106A:Card Game
题目链接http://codeforces.com/contest/106/problem/A 题意:一套牌有S.H.D.C四种花色,按等级分成6.7.8.9.T.J.Q.K.A.每次选出一个花色作为 ...
- java面试题11
第九次面试题 1. GC是什么?为什么要有GC? GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩 ...
- scrapy多线程文件下载
在爬取数据时有时候有些文件数据需要爬取下载下来使用多线程下载可以让程序跑的更快点. scrapy中有个扩展可以使用扩展模块来实现下载. 在自己的spider中加入 custom_settings cl ...
- [BZOJ3162]独钓寒江雪
bzoj description 你要给一个树上的每个点黑白染色,要求白点不相邻.求本质不同的染色方案数. 两种染色方案本质相同当且仅当对树重新标号后对应节点的颜色相同. \(n\le 5\times ...
- juqery学习3之juqery对象条件筛选
代码例子:某个div块下的字体样式的控制. //script代码 <script src="${sitePath}/cec_wcp/js/jquery-1.8.2.min.js&quo ...
- ES6必知必会 (九)—— Module
Module 1.ES6在语言标准的层面上,实现了模块功能,成为浏览器和服务器通用的模块解决方案,完全可以取代 CommonJS 和 AMD 规范,基本特点如下: 每一个模块只加载一次, 每一个JS只 ...
- aop学习
拦截器和过滤器的区别:https://blog.csdn.net/heyeqingquan/article/details/71482169 1,aop是一个编程思想,不是具体的实现,一般有Filte ...
- 网站配色、网站模板网址 UE样式 metro报表
http://www.colourlovers.com http://unmatchedstyle.com网站模板目录 花瓣 http://huaban.com/ 油表 http://fl ...
- jquery 绘图工具 flot 学习笔记
今天想做一个统计图表,像163博客的流量统计一样的,借助 flot 实现了,而且很简单. flot网址:http://code.google.com/p/flot/ 下载 JS 文件,使用方法和 jq ...