侧边栏壁纸
博主头像
落叶人生博主等级

走进秋风,寻找秋天的落叶

  • 累计撰写 130557 篇文章
  • 累计创建 28 个标签
  • 累计收到 9 条评论
标签搜索

目 录CONTENT

文章目录

springboot shiro实现权限管理

2023-12-14 星期四 / 0 评论 / 0 点赞 / 20 阅读 / 11740 字

记得第一次使用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 SupportWeb支持,可以非常容易的集成到Web环境,shiro本身不依赖于web环境;

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

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

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来搭建项目。

广告 广告

评论区