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 ...
随机推荐
- IIS服务器禁用缓存的方法
IIS服务器禁用缓存的方法: 工作中经常有实施的同事问我为什么界面皮肤图片替换后网站上没反应,要等很久才会出现结果.这个其实是服务器缓存的设置引起的问题,以前不知道怎么解决,临时的清缓存文件夹,有时候 ...
- 基于Jquery实现省份、城市、区县三级联动
前端感觉写的比较少,也是为了练手,下午没事用来写了这个三级联动,也是第一次写这东西. 据我了解,城市信息可以选择存在数据库或者直接写在前端,为了省事,我直接写在前端,下面是我的代码: <!DOC ...
- Java中,什么时候用logger.debuge,info,error
简单的说,就是配合log的等级过滤输出比如,你在开发的时候,要验证一个方法有没有被调用到,为了方便调试,通常会在这个方法开始的时候加一些system.out.但是项目真正发布的时候这些代码通常是要移除 ...
- java重写toString方法
在输出对象属性时,重写toString按照你希望的输出形式重写 object类里的toString只是把字符串的直接打印,数字的要转化成字符再打印,而对象,则直接打印该对象的hash码.所以当你要想按 ...
- Java编程之Map中分拣思想。
题目:给定一个字符串,求出字符串中每一个单词在字符串中出现的次数 旨意:map的分拣思想. 每一个key的包装类,存放出现的次数 /** * 作为包装类,用来存放英文单词,和该英文单词出现的次数 * ...
- APScheduler - Advanced Python Scheduler
简介 APScheduler:强大的任务调度工具,可以完成定时任务,周期任务等,它是跨平台的,用于取代Linux下的cron daemon或者Windows下的task scheduler. 内置三种 ...
- ballerina 学习二十三 扩展ballerina
扩展ballerina 目前有三种方式: 扩展client connector的包 (数据库访问,基础设施,api) 扩展server listenner 绑定为不同的协议 添加新的注解到baller ...
- 洛谷2148(SDOI2009) E&D
题目:https://www.luogu.org/problemnew/show/P2148 SG函数+找规律. 普通地用SG函数做. 每两堆是一个独立问题.因为虽然有可能一个人在同一组里连续操作2次 ...
- python 命令行参数获取
import argparse parser = argparse.ArgumentParser(description='Real-Time Filtering evaluation script ...
- Makefile编写 三 伪目标的作用
本节我们讨论一个Makefile中的一个重要的特殊目标:伪目标. 伪目标是这样一个目标:它不代表一个真正的文件名,在执行make时可以指定这个目标来执行其所在规则定义的命令,有时我们也可以将一个伪目标 ...