JWT与Shiro

已经用jwt做好了登录,客户要求用shiro做权限验证,懂一些技术的甲方,真的不好惹哦

JWT

其他文章介绍的也很多了,无非就是将用户的信息(一般包括唯一表示、过期时间等等),结合秘钥,用一定的加密算法进行加密,下次请求的时候就带上这个字符串(一般是在请求头中),服务器对其进行解密,就可以知道是哪个用户了,即有状态了。如果没有该字符串、或者解密失败、或者过期,就相应处理即可。

Shiro

文章: shiro框架详解讲了一大堆,看起来好像不错,但实际结合jwt应用时,就显得一头雾水。
结合github上Spring-Boot-Shiro的示例,简单分析总结一下。

怎么获取subject?

查看源码发现,subject可以通过AccessControlFilter中的getSubject(request, response)来获取,底部调用的是SecurityUtils中的getSubject():

public static Subject getSubject() {
        Subject subject = ThreadContext.getSubject();
        if (subject == null) {
            subject = (new Builder()).buildSubject();
            ThreadContext.bind(subject);
        }

        return subject;
    }

从源码可以看出,subject是从线程上下文中获取,如果不存在,则会新建一个。
其实,这也意味着,一个线程里面最多只有一个subject。

怎么标识subject?

由于subject是在线程中的,并且线程中最多只有一个subject,所以,其实不用标识subject的。
但是,不意味着该subject不需要登录。如果不执行

Subject.login(AuthenticationToken var1)

则在后续的权限验证中,会报错:

org.apache.shiro.authz.UnauthenticatedException: This subject is anonymous - it does not have any identifying principals and authorization operations require an identity to check against. 
A Subject instance will acquire these identifying principals automatically after a successful login is performed be executing org.apache.shiro.subject.Subject.login(AuthenticationToken) or when 'Remember Me' functionality is enabled by the SecurityManager.  
This exception can also occur when a previously logged-in Subject has logged out which makes it anonymous again.  Because an identity is currently not known due to any of these conditions, authorization is denied.

错误信息明确提示,subject没有标识(any identifying principals)。只有在Subject.login(AuthenticationToken) 或者’Remember Me’时,subject才会自动标识。

subject怎么登录?

由前文可知,subject是线程中的,所以,可以在springboot的拦截器或者过滤器中,让subject进行登录即可。
示例中,采用了Shiro官方的ShiroFilterFactoryBean,从名称上采用的就是过滤器,并在其中设置了url与过滤器的匹配关系:

		filterMap.put("jwt", new JWTFilter());
        factoryBean.setFilters(filterMap);
        /*
         * 自定义url规则
         * http://shiro.apache.org/web.html#urls-
         */
        Map<String, String> filterRuleMap = new HashMap<>();
        // 所有请求通过我们自己的JWT Filter
        filterRuleMap.put("/**", "jwt");

自定义的过滤器JWTFilter,继承了BasicHttpAuthenticationFilter,重写方法,并在其中执行了:

getSubject(request, response).login(token); 

注意,这里的token是实现了AuthenticationToken的实例,里面有getPrincipal() 和getCredentials()方法,即会为subject指定Principal和Credentials。
文章:Shiro身份认证(principals-credentials)中描述:

在shiro中,用户需要提供principals (身份)和credentials(证明)给shiro,从而应用能验证用户身份.
principals:身份即主体的标识属性,可以是任何东西.如用户名,邮箱等.唯一即可.一个主体可以有多个principals,但只有一个Primary principals,一般是用户名/密码/手机号。
credentials:证明/凭证,即只有主体知道的安全值。如密码
最常见的principals和credentials组合就是用户名、密码了。

简单得说,principals 可以认为是用户的唯一标识,可以是用户名称、用户id、或者是jwt的token都可以。credentials在这里就没有太大的意义了,因为在登录这块,jwt已经实现了功能。所以,随便指定一个值都是可以的。

注意,login具体执行的方法,是当前SecurityManager内,指定的AuthorizingRealm类中的doGetAuthenticationInfo方法。由于本次是有jwt进行登录,所以这里在实现时,可以不用进行判定,直接返回一个SimpleAuthenticationInfo,并在其中指定principals 和credentials,以及Realm的名字即可。

subject怎么校验权限

其实说subject校验权限是不正确的,因为校验权限,是由SecurityManager,指定的AuthorizingRealm类中的doGetAuthorizationInfo方法来获取权限,并由SecurityManager来进行判定的。
权限的获取,就比较简单了,直接看示例,获取角色和权限,并保存在SimpleAuthorizationInfo实例对象即可。

总结

配置文件中:
1.创建实例SecurityManager
2.SecurityManager中指定AuthorizingRealm
注意,示例中说,

/**
     * 大坑!,必须重写此方法,不然Shiro会报错
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JWTToken;
    }

具体原因还未尝试。
3.AuthorizingRealm中实现doGetAuthenticationInfo和doGetAuthorizationInfo
4.在config中定义好url与过滤器的对应关系
5.实现过滤器,继承BasicHttpAuthenticationFilter,以调用subject的login
在这里插入图片描述

注意事项

1.AuthorizingRealm必须重写supports(AuthenticationToken token) 方法
2.SecurityManager中需要关闭shiro自带的session,详情见文档 http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值