专栏首页企业平台构建springboot shiro实现权限管理

springboot shiro实现权限管理

记得第一次使用shiro是在才入行遇到公司的第一个框架,当时并不知道这是什么,或者说根本就没有安全框架的概念,在慢慢实践中,也对这个有了一定的了解,于是在网上找各种资料学习,了解。记得那时候比较有没的相关博客就是这个了,相信学习shiro的人很多都度过他的博客,内容也比较详细,示例也非常丰富。

开始使用shiro时,是与spring进行整合,可以看这里,当时没有实现太多功能,但是把一些外围的模块都已经实现,而且能够进行多realm匹配。在写这次博客前,也看了下renren-security,同样有很多可以借鉴的地方,所有既然看了这么多,那么自然要把功能做的完善一些了。

当然,此次的系统基础还是上次的springboot jpa搭建开发环境,我会在此基础上进行更新与扩展。

首先还是对shiro有一个初步的认识,当然这些认识都是收集与网络。

首先在学习这个框架时,都基本都会看到的图,那么我们需要了解的无非围绕着shiro里面这些核心的模块,具体是干什么,在什么时候,怎么去用,了解到这些之后,我们就可以按照自己的想法与设计,在适当的场合与环境下正确的使用该框架为我们提供的功能。

Authentication:身份认证/登录,验证用户是不是拥有相应的身份,该对象时对用户身份进行认证时,将相关信息存储的一个媒介,也是由开发者控制炎症逻辑的一个地方;

Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限,与上一个对象一起,都属于自定义Realm时需要由我们自己构建的;

Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的,在shiro是存在三种会话管理的工具,DefaultSessionManager,se环境会还管理;ServletContainerSessionManager,web环境,由web容器管理;DefaultWebSessionManager,支持以上两种,支持自定义会话管理。

Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储,在jar包中包含了大量操作密码的工具类;

Web Support:Web支持,可以非常容易的集成到Web环境,shiro本身不依赖于web环境;

Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;

Concurrency:shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;

Testing:提供测试支持;

Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;

Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。

更详细的信息可参考这个博客

在进行编码工作前,还是需要了解一些其他比较重要的 概念,我们知道,shiro的核心就是认证和鉴权,那么实现原理无非是通过servlet的Filter来完成的。其实过滤器是分为两类,一类是完成用户的身份与凭证验证,也就是用户名密码验证,保证能够登录系统,另一类则是权限验证的过滤器,主要是对接口、数据的权限校验。

其内置过滤器有如下这些:

anon:例子/admins/**=anon 没有参数,表示可以匿名使用。

authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,没有参数

roles(角色):例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。

perms(权限):例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。

rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] ,其中method为post,get,delete等。

port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString

是你访问的url里的?后面的参数。

authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证

ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https

user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查

当然我们还可以自定义一些。具体的说明可以参考这里

那么整合一个shiro框架我们具体需要添加哪些配置呢?如果和springmvc整合过的应该会比较清楚。当然,在shiro-spring这个包中,ShiroWebConfiguration、ShiroWebFilterConfiguration、ShiroAnnotationProcessorConfiguration已经有所有的内容,当然有一些是需要我们根据需要去修改的,毕竟默认的不一定能够满足我们的需要。

shiro基本可以当个黑盒使用,因为如何进行认证,如何进行全校校验已经由框架完成,留给开发者做的就是构建认证与鉴权需要的对象,而这些对象都是以realm的形式存在,我们只需要注入自定义的realm即可,简单的只用继承AuthorizingRealm这个类,实现抽象方法,doGetAuthenticationInfo为认证用的,我们需要构建认证对象,具体的逻辑由我们实现,doGetAuthorizationInfo为鉴权方法,当然是组织鉴权对象的方法。关于shiro,网上有太多太多的文章可以去参考,当然核心内容其实都是一样的。

说了这么多,是时候实际操作了,继续以之前的项目为基础,添加了一个security模块,同时将登入与主页路径进行了修改,因为是直接访问html,所以为了减去views这个路径,同时js也做了少量的修改:

核心其实都在security这包里,可以看到,内容其实不多,因为目前只是完成了认证,即用户登录的校验:

关于登录,有两种方式取实现:

1、自定义一个登录请求,自己完成token的定义与组织,同时完成login操作。这个时候我们会将/login.html过滤指向anon,同时登录行为请求也要设置成anon,本次就是通过这种方式实现:

@PostMapping("/dologin")
public Message login(HttpServletRequest request){
    String username = request.getParameter("username");
    String password = request.getParameter("password");
    String rememberMe = request.getParameter("rememberMe");
    Subject subject = SecurityUtils.getSubject();
    AuthenticationToken toker = new UsernamePasswordToken(username,password,rememberMe);
    Message message = new Message(Message.SUCCESS_CODE,username);
    try {
        boolean reLogin = true;//重新登录
        if(subject.isAuthenticated()){//已经登录如果再次登录
            if(reLogin){
                subject.logout();
            }else{
                return message;
            }
        }
        subject.login(toker);
    } catch (AuthenticationException e) {
        e.printStackTrace();
        message.setCode(Message.FAILURE_CODE);
        message.setInfo(loginFailure(e));
    }
    return message;
}

2、将登录页/login.html过滤器设置为authc(FormAuthenticationFilter),其实就是shiro专门为form表单提交的验证,这样需要我们在一定程度读上进行扩展,比如ajax提交时登录成功或失败的逻辑。但是要注意的是,提交的请求必须与登录页面地址一致,同时为POST类型。这个下次会用到,到时候可以看到具体实现。

然后看看realm:

public class GenericRealm extends AuthorizingRealm {
    @Autowired(required = false)
    private PrincipalService principalService;

    /**
     * 认证
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        Object principal = token.getPrincipal();
        if(principalService!=null){
            IUser user = principalService.getUser(principal.toString());
            if(user!=null){
                AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),"");
                return authenticationInfo;
            }
        }
        return null;
    }

    /**
     * 鉴权
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }
}

其实很简单,毕竟是构建对象的过程,所以没有太多的东西,所以关于与shiro的整合目前完成认证就这些东西,但是为了实现一个比较完整的认证授权功能,还有很多需要我们去了解与修改的,将会在下次进行完善。

在此次整合的过程中,也发现一个问题 ,以前和spring整合时,自定义的shiro filter是交由spring管理的,但是和springboot整合时,如果将filter交由spring管理则会出现异常,主要是由于在进行普通请求时也会进入该filter,但是我们要知道,shiro的核心是securityManager,很可能在一般的请求中还没有这个对象,自然就会出现问题,所以在个shiiro配置自定义过滤器时,直接通过new的方式添加即可。

同样,本次的代码在这里

本次项目花费的时间比较长,当然也不可能完成一个成形的项目,问题自然也就存在,但是毕竟是学习,存在一些遗留问题是必要的。目前该项目主要完成了简单的管理功能,如需要添加其他模块也有了一定的参考。由于后期有一些修改,所以之前页面有些写法可能还没来的及更新。

目前学习注重的是广度,因此基本每次进行了交叉方式来构建项目,比如这次用了springboot+jpa+shiro+layui,但是下次可能就不会用 相同的技术了,这样也是为了能快速对各种技术做个了解,并且能够快速上手。

下次将会通过springboot+springsecurity+mybatisplus+vue来搭建项目。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • [Swagger] Spring MVC 组件配置 之 Swagger整合

    架构探险之道
  • 【JVM学习资料之虚拟机栈中都有什么?】

    Java虚拟机栈(Java Virtual Machine Stacks) 是线程私有的,它的生命周期与线程相同。虚拟机栈为虚拟机执行Java方法(也就是字节码...

    用户5640963
  • Java 中的 "extends" 关键字

    继承之后,子类实例化之前会先执行被重载的父类方法overrideMe(),此时子类的实例化尚未完成,静态块也未执行,所以虽然是final修饰的字段,date变量...

    架构探险之道
  • JDK8 Lambda & Stream使用笔记

    手机用户请横屏获取最佳阅读体验,REFRENCES中是本文参考的链接,如需可百度"Yiyuery"获取CSDN或是我的个人博客地址,同步更新,文章中有对应的参考...

    架构探险之道
  • 【springMVC基础】spring获取bean的几种方法

    ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext....

    用户5640963
  • [Swagger] Springfox Swagger 项目接口自动化管理平台

    swagger相关maven文件放在公共父层,在parent-pom中,springfox的scope设置为provided,Springfox以及其依赖的ja...

    架构探险之道
  • 利用Metasploit破解Tomcat登录密码并通过war包部署Getshell

    Apache Tomcat 是世界上使用最广泛的Java Web应用服务器之一,绝大数人都会使用Tomcat的默认配置。然而默认配置中会有一个向外网开放的Web...

    7089bAt@PowerLi
  • Protocol Buffers 开发者指南

    欢迎来到 protocol buffers 的开发者指南。protocol buffers 是一个语言中立,平台中立针对通讯协议,数据存储和其他领域中对结构化数...

    HoneyMoose
  • [Swagger] Swagger 接口管理和文档导出

    title: date: 2018-08-25 19:22:00 categories:

    架构探险之道
  • Java的CopyOnWriteArrayList

    ArrayList并不是线程安全的,在读线程在读取ArrayList的时候如果有写线程在写数据的时候,基于fast-fail机制,会抛出ConcurrentMo...

    用户3467126

扫码关注云+社区

领取腾讯云代金券