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的更多相关文章

  1. Springboot shiro JWT集成总结

    SpringBoot Shiro JWT 1.建表 DDL.sql CREATE TABLE `t_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, ` ...

  2. SpringBoot+Shiro+JWT前后端分离实现用户权限和接口权限控制

    1. 引入需要的依赖 我使用的是原生jwt的依赖包,在maven仓库中有好多衍生的jwt依赖包,可自己在maven仓库中选择,实现大同小异. <dependency> <groupI ...

  3. 基于Shiro,JWT实现微信小程序登录完整例子

    小程序官方流程图如下,官方地址 : https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html ...

  4. 基于shiro+jwt的真正rest url权限管理,前后端分离

    代码地址如下:http://www.demodashi.com/demo/13277.html bootshiro & usthe bootshiro是基于springboot+shiro+j ...

  5. spring-boot-plus集成Shiro+JWT权限管理

    SpringBoot+Shiro+JWT权限管理 Shiro Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理. 使用Shiro的易于理解的API,您可以 ...

  6. 教你 Shiro + SpringBoot 整合 JWT

    本篇文章将教大家在 shiro + springBoot 的基础上整合 JWT (JSON Web Token) 如果对 shiro 如何整合 springBoot 还不了解的可以先去看我的上一篇文章 ...

  7. Shiro (Shiro + JWT + SpringBoot应用)

    Shiro (Shiro + JWT + SpringBoot应用) 目录 Shiro (Shiro + JWT + SpringBoot应用) 1.Shiro的简介 2.Shiro + JWT + ...

  8. SpringBoot集成JWT 实现接口权限认证

    JWT介绍 Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的, 特别适用于分布式站点 ...

  9. Shiro&Jwt验证

    此篇基于 SpringBoot 整合 Shiro & Jwt 进行鉴权 相关代码编写与解析 首先我们创建 JwtFilter 类 继承自 BasicHttpAuthenticationFilt ...

随机推荐

  1. 143. Long Live the Queen 树形dp 难度:0

    143. Long Live the Queen time limit per test: 0.25 sec. memory limit per test: 4096 KB The Queen of ...

  2. linux 网络测试命令 长期更新

    一.网络测试命令 1.测试 网络连接 发送两包后停发 [oracle@hadoop ~]$ PING www.a.shifen.com (() bytes of data. bytes from tt ...

  3. Faces人脸识别项目简介

    Faces人脸识别 分为两个模块,Faces文件夹下存放人脸识别算法的代码,Web文件夹下存放网站搭建的代码 详情请查看各个模块下的readme文档 项目简介 核心算法 一款基于Dlib.opencv ...

  4. SSRS 在订阅的时候,在头值中找到无效的字符。将不重新发送邮件

    在头值中找到无效的字符.将不重新发送邮件 SSRS 在订阅的时候,在头值中找到无效的字符.将不重新发送邮件! 查看了一下,只要是发送文件类型的都不可以,改成HTML的就可以.然后重新把RS的报表文件友 ...

  5. 关于apply、call和bind的总结

    基础知识不是你看了一遍书或者两篇文章就能掌握的. 之前看书看文章时,感觉自己看懂了就掌握了.呵呵!too young!too naive! 以前的坑还是要一铲一铲的填上的. 高程上面关于apply和c ...

  6. Robot Framework中使用HttpLibrary教程and中文支持

    Robot Framework中使用and转参数时,默认不支持中文模式,如图场景: 会出现这种错误 FAIL : UnicodeDecodeError: 'ascii' codec can't dec ...

  7. Julia 语言的一些尝试

    前些天发现了Julia 这门编程语言后便决定对其进行一些尝试,便写了下面的小程序,也算是看看这门语言所谓的速度快到底是怎么快法. 整数累加: x= function fff() : global x ...

  8. C语言——第四次作业(2)

    作业要求一 项目wordcount 设计思路:输入需统计的文件名,打开此文件,输入功能对应的字符,分别实现对应的功能,关闭文件. 主要代码 #include<stdio.h> #inclu ...

  9. 控制led灯并显示自己的数值

    前提是有led.jar包封装好了东西 1.并设置好led灯的模式并打开串口. 2.在布局中创建一个EditText ,Button.并利用-.getText.toString().trim(); 来获 ...

  10. AlertDialog中使用ListView绑定数据

    在实际工作过程中,单单使用AlertDialog的单选功能不一定能满足我们的需求,需要绑定数据到 listview 1. 自定义Layout LayoutInflater factory = Layo ...