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 ...
随机推荐
- 有效二叉查找树判断(java实现)
leetcode 原题 :(即判断二叉树是否为二叉查找树) Given a binary tree, determine if it is a valid binary search tree (BS ...
- 面筋: 奇虎360 c++ 后台开发 实习生 面试
投的是360上海的商业化部门,岗位是C++服务端开发实习生,记录一下面试历程: 视频面试,但是是有代码框让你写代码的. 一面: Q:先说一下个人信息,做过的项目 A:.......... Q:先写个翻 ...
- Beta阶段第1周/共2周 Scrum立会报告+燃尽图 06
作业要求与 [https://edu.cnblogs.com/campus/nenu/2018fall/homework/2284] 相同 版本控制:https://git.coding.net/li ...
- hadoop安装单机
java环境安装 http://www.cnblogs.com/zeze/p/5902124.html java 环境安装配置 etc/profile: export JAVA_HOME=/usr/j ...
- python中多进程
多进程 什么是进程 进程:正在进行的一个过程或者说一个任务,而负责执行任务的是CPU. 进程和程序的区别 程序仅仅是一堆代码而已,而进程指的是程序的运行过程. 举例 想象以为有着一手好厨艺的科学家肖亚 ...
- Linux运维学习笔记-目录知识点总结
目录知识点总结: Note: 1.创建一个/server/scripts目录,用于存放脚本(命令:mkdir -p /server/scripts) 2.安装软件时,安装路径统一为/usr/local ...
- Swift 获取plist文件展示在TableView上
// 1.定义二维数组 var data:[[String]]! override func viewDidLoad() { super.viewDidLoad() // 2.实例化tableView ...
- [QT]加快qt编译:设置默认多核编译qt
使用环境:win7 + QT Creator 4.2.1 + QT5.8 + MinGW5.3.0 32bit 设置默认多核编译qt 来源:http://stackoverflow.com/ques ...
- Fiddler显示响应时间 显示服务器IP
在主界面菜单上 Rules->CustomRules 在class Handlers{}里添加class 如: 显示响应时间 class Handlers { …… ) function Tim ...
- zipkin对于dubbo的支持
对于Web端: 1. 需要在applicationContext的头部添加中添加prefix引用: xmlns:dubbo="http://code.alibabatech.com/sche ...