推广

Spring Boot 中集成 Shiro

iseeyu3年前 (2024-02-21)推广152

1. Subject 为认证主体

包含 Principals 和 Credentials 两个信息。我们看下两者的具体含义。

Principals:代表身份。可以是用户名、邮件、手机号码等等,用来标识一个登录主体的身份。

Credentials:代表凭证。常见的有密码,数字证书等等。

说白了,两者代表了需要认证的内容,最常见的便是用户名、密码了。比如用户登录时,通过 Shiro 进行身份认证,其中就包括主体认证。

2. SecurityManager 为安全管理员

这是 Shiro 架构的核心,是 Shiro 内部所有原件的保护伞。项目中一般都会配置 SecurityManager,开发人员将大部分精力放在了 Subject 认证主体上,与 Subject 交互背后的安全操作,则由 SecurityManager 来完成。

3. Realm 是一个域

它是连接 Shiro 和具体应用的桥梁。当需要与安全数据交互时,比如用户账户、访控制等,Shiro 将会在一个或多个 Realm 中查找。我们可以把 Realm 看作 DataSource,即安全数据源。一般,我们会自己定制 Realm,下文会详细说明。

Shiro 身份和权限认证

1. Shiro 身份认证

我们分析下 Shiro 身份认证的过程,首先看一下官方给出的认证图。

从图中可以看到,这个过程包括五步

Step1:应用程序代码调用 Subject.login(token) 方法后,传入代表最终用户身份的 AuthenticationToken 实例 Token。

Step2:将 Subject 实例委托给应用程序的 SecurityManager(Shiro 的安全管理)并开始实际的认证工作。这里开始了真正的认证工作。

Step3、4、5:SecurityManager 根据具体的 Realm 进行安全认证。从图中可以看出,Realm 可进行自定义(Custom Realm)。

2. Shiro 权限认证

权限认证,也就是访问控制,即在应用中控制谁能访问哪些资源。在权限认证中,最核心的三个要素是:权限、角色和用户。它们之间的的关系可以用下图来表示:

一个用户可以有多个角色,而不同的角色可以有不同的权限,也可有相同的权限。比如说现在有三个角色,1 是普通角色,2 也是普通角色,3 是管理员,角色 1 只能查看信息,角色 2 只能添加信息,管理员对两者皆有权限,而且还可以删除信息。

Spring Boot 集成 Shiro

1. 依赖导入

Spring Boot 2.0.3 集成 Shiro 需要导入如下 starter 依赖:

2. 数据库表的建立及初始化

这里主要涉及到三张表:用户表、角色表和权限表。其实在 Demo 中,我们完全可以自己来模拟数据库操作,不用建表,但为了更加接近实际情况,我们还是引入了 MyBatis 来操作数据库。下面是数据库各表的创建脚本。

CREATE TABLE `t_role` (

`id` int(11) NOT NULL AUTO_INCREMENT COMMENT ‘主键’,

`rolename` varchar(20) DEFAULT NULL COMMENT ‘角色名称’,

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

CREATE TABLE `t_user` (

`id` int(11) NOT NULL AUTO_INCREMENT COMMENT ‘用户主键’,

`username` varchar(20) NOT NULL COMMENT ‘用户名’,

`password` varchar(20) NOT NULL COMMENT ‘密码’,

`role_id` int(11) DEFAULT NULL COMMENT ‘外键关联role表’,

PRIMARY KEY (`id`),

KEY `role_id` (`role_id`),

CONSTRAINT `t_user_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `t_role` (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

CREATE TABLE `t_permission` (

`id` int(11) NOT NULL AUTO_INCREMENT COMMENT ‘主键’,

`permissionname` varchar(50) NOT NULL COMMENT ‘权限名’,

`role_id` int(11) DEFAULT NULL COMMENT ‘外键关联role’,

PRIMARY KEY (`id`),

KEY `role_id` (`role_id`),

CONSTRAINT `t_permission_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `t_role` (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8

其中,t_user、t_role 和 t_permission 分别存储了用户信息、角色信息和权限信息,表建立好后,我们往表里插入一些测试数据,比如下面这些数据。

t_user 表:

t_role 表:

t_permission 表:

解释一下这里的权限:user:* 表示权限可以是 user:create 或其他,* 表示一个占位符,可以自己定义,下文介绍 Shiro 配置时会对其再做详细说明。

3. 自定义 Realm

有了数据库表和数据,我们开始自定义 Realm。自定义 Realm 需要继承 AuthorizingRealm 类,该类封装了很多方法,且继承自 Realm 类。

继承 AuthorizingRealm 类后,我们需要重写以下两个方法。

1)doGetAuthenticationInfo() 方法:用来验证当前登录的用户,获取认证信息。

2)doGetAuthorizationInfo() 方法:为当前登录成功的用户授予权限和分配角色。

具体实现如下,相关注解请见代码注释:

public class MyRealm extends AuthorizingRealm {

    @Resource

    private UserService userService;

    @Override

    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        // 获取用户名

String username = (String) principalCollection.getPrimaryPrincipal();

SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

        // 给该用户设置角色,角色信息存在 t_role 表中取

authorizationInfo.setRoles(userService.getRoles(username));

        // 给该用户设置权限,权限信息存在 t_permission 表中取

authorizationInfo.setStringPermissions(userService.getPermissions(username));

        return authorizationInfo;

}

    @Override

    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        // 根据 Token 获取用户名,如果您不知道该 Token 怎么来的,先可以不管,下文会解释

String username = (String) authenticationToken.getPrincipal();

        // 根据用户名从数据库中查询该用户

User user = userService.getByUsername(username);

        if(user != null) {

        // 把当前用户存到 Session 中

SecurityUtils.getSubject().getSession().setAttribute(“user”, user);

            // 传入用户名和密码进行身份认证,并返回认证信息

AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), “myRealm”);

            return authcInfo;

} else {

            return null;

}

}

}

从上面两个方法中可以看出,验证身份时需先根据用户输入的用户名从数据库中查出对应的用户,这时还未涉及到密码,也就是说即使用户输入的密码不正确,照样可以查询出该用户。

然后,将该用户的相关信息封装到 authcInfo 中并返回给 Shiro。接下来就该 Shiro 上场了,将封装的用户信息与用户的输入信息(用户名、密码)进行对比、校验(注意,这里对密码也要进行校验)。校验通过则允许用户登录,否则跳转到指定页面。

同理,权限验证时,也需先根据用户名从数据库中获取其对应的角色和权限,将其封装到 authorizationInfo 并返回给 Shiro。

4. Shiro 配置

自定义 Realm 写好了,接下来需要配置 Shiro。我们主要配置三个东西:自定义 Realm、安全管理器 SecurityManager 和 Shiro 过滤器。

首先,配置自定义的 Realm,代码如下:

接着,配置安全管理器 SecurityManager:

@Configuration

public class ShiroConfig {

    @Bean

        public SecurityManager securityManager() {

        // 将自定义 Realm 加进来

DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(myAuthRealm());

logger.info(“====securityManager注册完成====”);

        return securityManager;

}

}

配置 SecurityManager 时,需要将上面自定义 Realm 添加进来,这样 Shiro 才可访问该 Realm。最后,配置 Shiro 过滤器:

@Configuration

public class ShiroConfig {

    @Bean

    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {

        // 定义 shiroFactoryBean

ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();

        // 设置自定义的 securityManager

shiroFilterFactoryBean.setSecurityManager(securityManager);

        // 设置默认登录的 URL,身份认证失败会访问该 URL

shiroFilterFactoryBean.setLoginUrl(“/login”);

        // 设置成功之后要跳转的链接

shiroFilterFactoryBean.setSuccessUrl(“/success”);

        // 设置未授权界面,权限认证失败会访问该 URL

shiroFilterFactoryBean.setUnauthorizedUrl(“/unauthorized”);

        // LinkedHashMap 是有序的,进行顺序拦截器配置

Map filterChainMap = new LinkedHashMap<>();

        // 配置可以匿名访问的地址,可以根据实际情况自己添加,放行一些静态资源等,anon 表示放行

filterChainMap.put(“/css/**”, “anon”);

filterChainMap.put(“/imgs/**”, “anon”);

filterChainMap.put(“/js/**”, “anon”);

filterChainMap.put(“/swagger-*/**”, “anon”);

filterChainMap.put(“/swagger-ui.html/**”, “anon”);

        // 登录 URL 放行

filterChainMap.put(“/login”, “anon”);

        // 以“/user/admin” 开头的用户需要身份认证,authc 表示要进行身份认证

filterChainMap.put(“/user/admin*”, “authc”);

        // “/user/student” 开头的用户需要角色认证,是“admin”才允许

filterChainMap.put(“/user/student*/**”, “roles[admin]”);

        // “/user/teacher” 开头的用户需要权限认证,是“user:create”才允许

filterChainMap.put(“/user/teacher*/**”, “perms[\”user:create\”]”);

        // 配置 logout 过滤器

filterChainMap.put(“/logout”, “logout”);

        // 设置 shiroFilterFactoryBean 的 FilterChainDefinitionMap

shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);

      return shiroFilterFactoryBean;

}

}

配置 Shiro 过滤器时,我们引入了安全管理器。至此,我们可以看出,Shiro 配置一环套一环,遵循从 Reaml 到 SecurityManager 再到 Filter 的过程。在过滤器中,我们需要定义一个 shiroFactoryBean,然后将 SecurityManager 引入其中,需要配置的内容主要有以下几项。

今天就分享到这,Shiro不太好懂,大家好好消化一下:关于Springboot中集成Shiro大家有没有什么问题?

扫描二维码推送至手机访问。

版权声明:本文由西安泽虎代运营发布,如需转载请注明出处。

转载请注明出处https://www.0291.com.cn/post/57604.html

相关文章

惊!美国女网红自曝淫乱私生活!和亲妈共侍一

惊!美国女网红自曝淫乱私生活!和亲妈共侍一

情侣间的相处方式很多,有一些方式可能会超越一般人的理解! 美国抖音网红玛迪(Madi Brooks)在短片上分享,指自己没有心情时就会让丈夫与岳母发生关系,镜头一转更看到丈夫从后亲密地熊抱岳母。 在玛迪的开放式关系之中,与她分享丈夫的人还包括她的妹妹,换言之,玛迪与妈妈及妹妹3人共享1男子。...

站外SEO优化该怎样做?掌握这些SEO优化策略,让网站权重提升一个level

站外SEO优化该怎样做?掌握这些SEO优化策略,让网站权重提升一个level

当你辛苦做完站内之後,网站排名依然无法排在Google结果页的靠前排名?这可能与站外SEO优化有关! 今天,Inspirr网页制作就为大家简单介绍站外SEO优化的几个重点,助你轻松提高网页SEO权重,使Google更加重视你的网页,让网站更快地排到靠前位置,从而获得更好的网站SEO成效。 站外S...

活动运营|不就是写个活动运营方案

编辑导语:活动运营方案是做活动时不可或缺的一部分,不管是在汇报还是执行方面都起着举足轻重的作用,关系到活动能否顺利进行。这篇文章讲述了活动方案的作用和十要素,帮助大家把方案做得完善。 无论做什么拉新、促销的运营活动,多少都离不...

SEO的职业生涯:从seo初级水平到seo资源整合营销总监的历程。

SEO的职业生涯:从seo初级水平到seo资源整合营销总监的历程。

首先,SEO的价值是以最低的成本从搜索引擎获得最大的流量和客户,然后实现销售。 当然,流量和用户不仅仅是搜索引擎。庞大的互联网上到处都是流量和用户。最熟悉的是QQ、微信、微博、阿里部门、头条新闻、门户网站等。因此,通常的SEO已经成为一个多功能排水营销站的SEO旗下,甚至交易和后续客户维护进入SE...

什么是真正的「富人思维」?

什么是真正的「富人思维」?

穷人optimize,富人玩儿constraint。这只是个模型,但很有用。先谈optimizationoptimization思想产生的环境,是相对封闭、单一的群体竞争环境。没错,就是应试教育制度。每个人的行为,都是源自他们对这个世界游戏规则的理解。不上进的x丝理解的规则...

企业网络推广优化要怎么做关键词排名。

企业网络推广优化要怎么做关键词排名。

随着社会不断地发展中,现今做网络推广排名优化的企业数量都变得越来越多,而今做网站推广优化要想可以在搜索引擎中获得更多的权重和排名,那么站长们在优化中还得注重更多的优化细节和SEO技巧,企业网络推广优化要怎么做关键词排名? 一、网站导航栏目存在的意义 首先,我们应该清楚网站栏目存在的意义...

现在,非常期待与您的又一次邂逅

我们努力让每一部企业宣传片和抖音短视频成为商业大片