【安全框架系列】
前言
在Web开发中,安全是第一位!
在做网站的过程中,安全应该在设计之初就进行考虑。
在以往的开发中,我们可以通过配置一些过滤器与拦截器来实现一些简单的安全操作,但是过滤器和拦截器的使用需要编写大量的原生代码,使得项目过于繁琐,产生冗余
接下来我们学习两个常用的安全框架:SpringSecurity、Shiro
笔记作于跟随 狂神说Java b站视频学习过程中
SpringSecurity
简介
官网:https://spring.io/projects/spring-security
官方文档:https://docs.spring.io/spring-security/site/docs/5.3.3.BUILD-SNAPSHOT/reference/html5/
Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。 它是用于保护基于Spring的应用程序的实际标准。 Spring Security是一个框架,致力于为Java应用程序提供身份验证和授权。 与所有Spring项目一样,Spring Security的真正强大之处在于可以轻松扩展以满足自定义要求(翻译~)
Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications.
Spring Security is a framework that focuses on providing both authentication and authorization to Java applications. Like all Spring projects, the real power of Spring Security is found in how easily it can be extended to meet custom requirements
几个重要的类:
WebSecurityConfigurerAdapter
:自定义Security策略AutnenticationManagerBuilder
:自定义认证模式@EnableWebSecurity
:开启WebSecurity模式
SpringSecurity的主要任务:
- 认证(Authentication)
- 授权(Authorization)
本质:
采用 AOP 将安全组件横切进去,不影响业务逻辑!
认证与授权
1. 环境搭建
2. 导入依赖
1 | <dependency> |
3. 编写配置类
1 |
|
4. 运行测试
- 初次访问各 level页面 时会跳转到登陆页面,需要进行登陆操作
登陆用户 “wxshhh”
- level1的所有页面可以正常访问
- level2的所有页面也可以正常访问
- level3的页面报错:403
结果与配置结果一致,配置成功!
注销用户
1
2
3
4<!-- 设置注销页面的请求路径:/logout -->
<a class="item" th:href="@{/logout}">
<i class="sign-out icon"></i> 注销
</a>跳转到注销页面:
确认注销之后跳转到登陆页面:
Thymeleaf 与 SpringSecurity 整合
导入依赖
1
2
3
4
5
6<!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity4 -->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>3.0.2.RELEASE</version>
</dependency>修改 index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21<!--登录注销-->
<div class="right menu">
<!--未登录,只显示登陆按钮-->
<div sec:authorize="!isAuthenticated()">
<a class="item" th:href="@{/toLogin}">
<i class="address card icon"></i> 登录
</a>
</div>
<!--已登录,显示用户名和注销按钮-->
<div sec:authorize="isAuthenticated()">
<a class="item">
用户名:<span sec:authentication="name"></span>
</a>
<a class="item" th:href="@{/logout}">
<i class="sign-out icon"></i> 注销
</a>
</div>
</div>1
2
3
4
5
6
7
8
9
10
11
12
13
14<!-- 根据用户角色的不同显示不同的菜单 -->
<div class="ui three column stackable grid">
<div class="column" sec:authorize="hasRole('vip1')">
……
</div>
<div class="column" sec:authorize="hasRole('vip2')">
……
</div>
<div class="column" sec:authorize="hasRole('vip3')">
……
</div>
</div>==注意!要使用较低版本的SpringBoot==
Shiro
简介
Apache Shiro™是一个功能强大且易于使用的Java安全框架,它执行身份验证,授权,加密和会话管理。 使用Shiro易于理解的API,您可以快速轻松地保护任何应用程序-从最小的移动应用程序到最大的Web和企业应用程序。
Apache Shiro™ is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, and session management. With Shiro’s easy-to-understand API, you can quickly and easily secure any application – from the smallest mobile applications to the largest web and enterprise applications.
Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在 JavaSE 环境,也可以用在 JavaEE 环境。Shiro 可以帮助我们完成:认证、授权、加密、会话管理、与 Web 集成、缓存等。
其基本功能如下图所示:
Authentication:身份认证 / 登录,验证用户是不是拥有相应的身份;
Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;
Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通 JavaSE 环境的,也可以是如 Web 环境的;
Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
Web Support:Web 支持,可以非常容易的集成到 Web 环境;
Caching:缓存,比如用户登录后,其用户信息、拥有的角色 / 权限不必每次去查,这样可以提高效率;
Concurrency:shiro 支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;
Testing:提供测试支持;
Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;
Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。
Shiro外部:
Subject:主体,代表了当前 “用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是 Subject,如网络爬虫,机器人等;即一个抽象概念;所有 Subject 都绑定到 SecurityManager,与 Subject 的所有交互都会委托给 SecurityManager;可以把 Subject 认为是一个门面;SecurityManager 才是实际的执行者;
SecurityManager:安全管理器;即所有与安全有关的操作都会与 SecurityManager 交互;且它管理着所有 Subject;可以看出它是 Shiro 的核心,它负责与后边介绍的其他组件进行交互,如果学习过 SpringMVC,你可以把它看成 DispatcherServlet 前端控制器;
Realm:域,Shiro 从从 Realm 获取安全数据(如用户、角色、权限),就是说 SecurityManager 要验证用户身份,那么它需要从 Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从 Realm 得到用户相应的角色 / 权限进行验证用户是否能进行操作;可以把 Realm 看成 DataSource,即安全数据源。
快速开始
导入依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.26</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>配置文件 shiro.ini
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33# -----------------------------------------------------------------------------
# Users and their assigned roles
#
# Each line conforms to the format defined in the
# org.apache.shiro.realm.text.TextConfigurationRealm#setUserDefinitions JavaDoc
# -----------------------------------------------------------------------------
[users]
# user 'root' with password 'secret' and the 'admin' role
root = secret, admin
# user 'guest' with the password 'guest' and the 'guest' role
guest = guest, guest
# user 'presidentskroob' with password '12345' ("That's the same combination on
# my luggage!!!" ;)), and role 'president'
presidentskroob = 12345, president
# user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz'
darkhelmet = ludicrousspeed, darklord, schwartz
# user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz'
lonestarr = vespa, goodguy, schwartz
# -----------------------------------------------------------------------------
# Roles with assigned permissions
#
# Each line conforms to the format defined in the
# org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc
# -----------------------------------------------------------------------------
[roles]
# 'admin' role has all permissions, indicated by the wildcard '*'
admin = *
# The 'schwartz' role can do anything (*) with any lightsaber:
schwartz = lightsaber:*
# The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with
# license plate 'eagle5' (instance specific id)
goodguy = winnebago:drive:eagle5HelloWord(部分重要代码)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20// get the currently executing user:
Subject currentUser = SecurityUtils.getSubject();
Session session = currentUser.getSession();
if (!currentUser.isAuthenticated()) {
……
}
currentUser.getPrincipal();
if (currentUser.hasRole("schwartz")) {
……
}
if (currentUser.isPermitted("lightsaber:wield")) {
……
}
currentUser.logout();SpringSecurity 中都有,只是名字变了!
集成SpringBoot
1. 环境准备
2. 导入依赖
1 | <!-- spring-shiro --> |
3. 编写配置类
从下往上编写
1 | package com.wxshhh.config; |
1 | package com.wxshhh.config; |
4. 实现登陆拦截
1 | public ShiroFilterFactoryBean getShiroFilterFactoryBean( { DefaultWebSecurityManager defaultWebSecurityManager) |
5. 实现用户认证
IndexController:
1 |
|
UserRealm
1 | //认证 |
6. 实现权限控制
ShiroConfig:
1 |
|
UserRealm
1 | //授权 |
完结!!!
狂神,永远滴神!!!
参考
狂神说Java:https://www.bilibili.com/video/BV1NE411i7S8
w3cschool:https://www.w3cschool.cn/shiro/