1.项目环境

jdk:8 
springboot:1.5.10.RELEASE

2.简述处理过程

  • 前端请求登录,传入用户名userName和密码password和令牌token
  • 后端进入jwtFilter拦截,判断当前请求中是否是登录请求(可以通过是否存在token,也可以通过判断请求的地址是否是登录地址)
  • 如果是登录请求,就不执行shiro认证和授权,直接进入控制器进行帐号和密码校验,校验成功生成token返回;
  • 如果是非登录请求,jwtFilter执行executeLogin方法进入自定义realm进行认证doGetAuthenticationInfo(认证不通过,抛出异常,异常的处理稍后详细说明)和授权doGetAuthorizationInfo,都通过然后进入自己的控制器;

好了,说到这已经看起来很简单了,下面就开启hello world了,简单说明下具体执行细节及处理各种情况应对策略:

3.开始搭建项目

编辑器不能带有代码主题样式难看的要死,作为有洁癖程序员不能忍,只好上传图片以表慰藉,需要源码demo去最后下载就行

  1. 首先,新建springboot项目,引入如下依赖
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.2.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.2.5</version>
        </dependency>
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.2.0</version>
        </dependency>

简单说明下:shiro-ehcache是shiro处理缓存,java-jwt是用来做请求拦截,分发认证和授权;

  1. jwt配置(网上一大堆,自需取就行了)
token令牌

springboot api 鉴权 springboot 权限验证_springboot


简单翻下源码:AuthenticationToken接口的实现默认是UsernamePasswordToken(这个是在前后端不分离的情况下使用),而getPrincipal()方法返回的是帐号,getCredentials()返回的是密码,咱这类比下,getPrincipal()getCredentials()咱们全部用token代替,有了这个咱们就能取到帐号了,这2个方法会在我们自定义的realm中用得到,继续往下走~~,

springboot api 鉴权 springboot 权限验证_springboot_02


springboot api 鉴权 springboot 权限验证_jwt_03

JWTUtils:用来生成token,校验token,从token中获取登录名,没什么说的

springboot api 鉴权 springboot 权限验证_jwt_04

注意:生成token和校验token中的密码必须保持一致(这里采用加密后的值)

继续继续~~~~~下面的重点来了

JWTFilter:既然是filter,那么自然就是拦截请求了

springboot api 鉴权 springboot 权限验证_springboot_05


咱们看看执行过程,打断点可以看到,先进的是isAccessAllowed,有兴趣可以追源码,这就不多说了,在这个方法中有2个操作

  1. 判断是否是登录请求isLoginAttempt这里通过判断请求的请求头中是否存在token,没有return false,直接进入控制器,校验成功返回token到前端,前端拿到token后,下次非登录请求就需要携带token,这里的R类就是一个封装的haskMap
  2. springboot api 鉴权 springboot 权限验证_springboot api 鉴权_06


  3. springboot api 鉴权 springboot 权限验证_前后端分离_07

  4. 如果有token,既为非登录请求,执行第二个方法
  5. 执行登录认证和授权executeLogin这个里边有个getSubject(request, response).login(token)方法,这个方法的执行就会到咱们自定的realm中,执行认证和授权
  6. 自定义realm
  7. 重写supports
  8. springboot api 鉴权 springboot 权限验证_springboot api 鉴权_08

  9. 认证:这里有个说明下,由于帐号的校验放到控制层的login方法中,这里直接return new SimpleAuthenticationInfo(token, token, getName()); 这个方法就不会抛出帐号相关的异常,因为2个参数token值以同一个;
  10. 授权:说明下,这个方法的执行是在有shiro注解标签(如:@RequiresPermissions("sys:user:save"))的前提下才会调用,如果配有缓存,这个方法再调用一次后,授于的角色和权限将存在缓存,下次请求就不会进入这个方法;继续,在拿到权限后,进入控制器,校验注解权限是否合法,完成权限校验
  11. 拿到token后执行其他操作,发送请求

springboot api 鉴权 springboot 权限验证_springboot api 鉴权_09


进入授权(如果缓存没有授权,这里会先进入缓存判断),进入授权

springboot api 鉴权 springboot 权限验证_前后端分离_10


springboot api 鉴权 springboot 权限验证_springboot_11


授权后进入控制器,完成操作

springboot api 鉴权 springboot 权限验证_springboot api 鉴权_12


springboot api 鉴权 springboot 权限验证_shiro_13


如果权限不足:

springboot api 鉴权 springboot 权限验证_jwt_14

3.存在哪些问题?

  1. 在认证过程中(执行realmdoGetAuthenticationInfo),发现token非法,此时异常如何处理?
    如果出现token非法(比如密码修改了,但token还是之前密码生成的),此时异常将被 JWTFilterisAccessAllowed捕获,并抛出,该方法并没有自动上抛,需要手动抛出,此时这个异常是filter抛出(跟踪源码到AdviceFilterdoFilterInternal方法中boolean continueChain = preHandle(request, response)抛出),发现@RestControllerAdvice并不能接收到改异常进行处理,此时需要配合BasicErrorController进行处理,和下2一致;
  2. 当认证和授权都通过时,发现控制器中的方法执行权限不足,这个异常如何捕获?
    通过BasicErrorController@RestControllerAdvice配合进行异常捕获
    GlobalFilterExceptionHandler将JWTFilter中的isAccessAllowed方法中抛出的异常进行取出,然后丢给GlobalExceptionHandler处理即可;

springboot api 鉴权 springboot 权限验证_shiro_15

用户密码生成:

springboot api 鉴权 springboot 权限验证_jwt_16

4.demo下载

sringboot+jwt+shiro demo