在Web应用中安全问题同样不可忽视,所以Spring Framework体系中也为此提供了解决方案——Spring Security。但是由于其较为复杂,新人上手较为困难。所以这里我们来介绍另外一个简单易用的开源安全框架——Apache Shiro,并说明如何在SpringBoot中实现身份认证、权限授权
配置
Maven依赖
在Pom.xml添加Shiro Framework依赖
1 | <!-- Shiro Framework --> |
自定义令牌
相比较每次HTTP请求通过用户名、密码来进行身份认证,使用后端生成的Token则会更加安全、方便,为此我们需要先自定义一个基于Token的令牌以用于身份认证,如下所示
1 | /** |
自定义拦截器 Filter
为保证Web应用安全,不被非法访问攻击。我们还需要自定义一个拦截器Filter,其作用就是使得HTTP请求在到达指定的Contorller之前被拦截以便进行认证、授权等任务。这里我们通过继承AuthenticatingFilter定义了一个我们自己的拦截器CustomFilter。在拦截器中,如果我们发现请求头中包含token字段(携带令牌),则予以放行说明该请求可以进行认证、授权任务;反之则在拦截器中直接过滤掉该请求
1 | /** |
自定义Realm
在Shiro中有一个Realm的概念,通过它来可以完成认证、授权等任务的具体逻辑。一般地,我们需要根据自己的实际业务需求来实现它,换句话说,Realm就相当于是一个安全相关的Dao。这里我们通过继承AuthorizingRealm类实现了一个自定义的Realm类,我们需要重写父类的doGetAuthenticationInfo、doGetAuthorizationInfo方法来定义我们的身份认证、权限授权的具体逻辑。在前文中,我们定义了一个自定义令牌——CustomToken,所以这里通过重写supports方法来只使用我们自定义的令牌
1 | /** |
配置Shiro
至此,我们已经把Shiro的相关组件——Token、Filter、Realm,均已经配置完成,现在只需将它们装配在一起即可。示例如下所示,除login登录接口(该接口接收用户名、密码信息来返回token)外,其他接口均需要先进行身份认证
1 | /** |
身份认证
所谓认证就如我们在CustomRealm的doGetAuthenticationInfo方法中的逻辑一样,即判断该请求携带的Token数据是否能查询到相关的用户。如果能则说明身份认证成功;反之则不能。这里问为认证测试提供了一个Controller
1 |
|
现在我们通过PostMan来进行测试
1. 请求login接口
通过登录接口分别获取到用户Aaron、Bob的token信息为abcdefg、kfc
2. 请求testAuthen接口
当我们不携带token、携带错误的token发起请求时,可以看到会导致认证失败,接口没有响应
当我们携带正确的token发起请求时,则可以看到认证成功,接口正常响应
权限控制
这里为了便于演示,我们建立了一个简单的用户-权限表,如下图所示
从中我们可以得知:
- 用户Aaron,其Token为abcdefg,角色为user用户,权限为accessPerm1
- 用户Bob,其Token为kfc,角色为root用户,权限为accessPerm2
基于角色的授权
正如我们在CustomRealm的doGetAuthorizationInfo方法中的所做的那样,我们在认证通过之后会为其添加角色、权限相关的信息。在Shiro中可以通过@RequiresRoles注解来方便地表示访问Controller需要的角色条件,这里我们提供了testAuthor1、testAuthor2两个请求接口,前者只能是user用户可以访问,而后者只能是root用户才可以访问
1 |
|
现在我们通过PostMan来进行测试testAuthor1接口:
- 当我们不携带token、携带错误的token发起请求时,可以看到会同样导致认证失败,接口没有响应
- 当Aaron访问时,由于其角色为user用户,故接口被正确响应
- 当Bob访问时,虽然认证通过了,但是由于其角色为root用户,没有权限访问该接口,故该接口没有响应
基于权限的授权
在Shiro中也可以通过@RequiresPermissions注解来方便地表示访问Controller需要的权限条件,这里我们提供了testAuthor3、testAuthor4两个请求接口,前者只能是拥有accessPerm1权限的用户可以访问,而后者只能是拥有accessPerm2权限的用户可以访问
1 |
|
现在我们通过PostMan来进行测试testAuthor3接口:
- 当Aaron访问时,由于其权限条件为accessPerm1,故接口被正确响应
- 当Bob访问时,虽然认证通过了,但是由于其只有accessPerm2的权限条件,故该接口没有响应