1、什么是安全管理框架?
解决系统安全问题的框架。如果没有安全框架,我们需要手动处理每个资源的访问控制,非常麻烦。使 用安全框架,我们可以通过配置的方式实现对资源的访问限制。 安全框架,简单说是对访问权限进行控制,应用的安全性包括用户认证(Authentication)和用户授权 (Authorization)两个部分。
安全框架能做什么?
登录验证 —— 轻松登录鉴权,并提供五种细分场景值
权限验证 —— 适配RBAC权限模型,不同角色不同授权
踢人下线 —— 将违规用户立刻清退下线
持久层扩展 —— 可集成Redis、Memcached等专业缓存中间件,重启数据不丢失
分布式会话 —— 提供jwt集成和共享数据中心两种分布式会话方案
单点登录 —— 一处登录,处处通行
注解式鉴权 —— 优雅的将鉴权与业务代码分离
路由拦截式鉴权 —— 根据路由拦截鉴权,可适配restful模式
会话治理 —— 提供方便灵活的会话查询接口
记住我模式 —— 适配[记住我]模式,重启浏览器免验证
密码加密 —— 提供密码加密模块,可快速MD5、SHA1、SHA256、AES、RSA加密
组件自动注入 —— 零配置与Spring等框架集成
2、企业中使用的主流安全框架
市面上主流的安全管理框架Shiro、SpringSecurity、Sa-Token
在sping boot发布之前之前shiro是市场的绝对主流 直到有一天 Spring Boot 像谜一般出现在江湖边缘,彻底颠覆了 JavaEE 的世界。一人得道鸡犬升天,自 从 Spring Boot 火了之后,Spring 家族的产品都被带了一把,Spring Security 就是受益者之一,从此飞 上枝头变凤凰。
Spring Boot/Spring Cloud 现在作为 Java 开发领域最最主流的技术栈,这一点大家应该都没有什么异 议,而在 Spring Boot/Spring Cloud 中做安全管理,Spring Security 无疑是最方便的。 而sa-Token呢,则算是后期之秀,与其他框架相比
1. 简单 :可零配置启动框架,真正的开箱即用,低成本上手
2. 强大 :目前已集成几十项权限相关特性,涵盖了大部分业务场景的解决方案
3. 易用 :如丝般顺滑的API调用,大量高级特性统统只需一行代码即可实现
4. 高扩展 :几乎所有组件都提供了扩展接口,90%以上的逻辑都可以按需重写
首先我要声明一点,框架无所谓好坏,关键是适合当前项目场景,作为一个年轻的程序员更不应该厚此 薄彼,或者拒绝学习某一个框架。 小孩子才做选择题,成年人两个都要学!
3.为什么选择spring security?
功能全:API完整;成熟的身份认证和用户授权方案;支持缓存;可以前后端分离,适应市场;可 以单独使用 搭配技术多:配合spring boot,JWT,OAuth2 授权服务,RBAC角色访问模型等技术或模型更方 便快捷 社区资源丰富:遇到问题,可以轻松找到成熟的解决方案;学习资料容易获取; 对于spring更友好:充分利用Spring IoC,DI,和AOP的功能
「有的人觉得 Spring Security 配置臃肿。」
如果是 SSM + Spring Security 的话,我觉得这话有一定道理。但是如果是 Spring Boot 项目的话,其实 并不见得臃肿。Spring Boot 中,通过自动化配置 starter 已经极大的简化了 Spring Security 的配置, 我们只需要做少量的定制的就可以实现认证和授权了,一会大家看我给大家演示快速入门就知道了
「有人觉得 Spring Security 中概念复杂。」
这个是这样的,没错。
Spring Security 由于功能比较多,就显得比较重量级,不像 Shiro 那样轻便。 但是如果换一个角度,你可能会有不一样的感受。 在 Spring Security 中你会学习到许多安全管理相关的概念,以及常见的安全攻击。这些安全攻击,如果 你不是 web 安全方面的专家,很多可能存在的 web 攻击和漏洞你可能很难想到,而 Spring Security 则 把这些安全问题都给我们罗列出来并且给出了相应的解决方案。 所以我说,我们学习 Spring Security 的过程,也是在学习 web 安全,各种各样的安全攻击、各种各样 的登录方式、各种各样你能想到或者想不到的安全问题,Spring Security 都给我们罗列出来了,并且给 出了解决方案,从这个角度来看,你会发现 Spring Security 好像也不是那么让人讨厌。
结合微服务的优势
除了前面和大家介绍的 Spring Security 优势,在微服务中,Spring 官方推出了 Spring Cloud Security
和 Spring Cloud OAuth2,结合微服务这种分布式特性,可以让我们更加方便的在微服务中使用 Spring Security 和 OAuth2
可以看到,Spring 官方一直在积极进取,让 Spring Security 能够更好的集成进微服务中。
、怎么开始学习Spring Security
具体参考教程:后台系统权限管理设计实战
Spring Security快速入门
1、导入依赖
Spring Security已经被Spring boot进行集成,使用时直接引入启动器即可。
org.springframework.boot
spring-boot-starter-security
2、访问页面
导入spring-boot-starter-security启动器后,Spring Security已经生效,默认拦截全部请求,如果用户 没有登录,跳转到内置登录页面。 在项目中新建login.html页面后 在浏览器输入:http://localhost:8080/login.html后会显示下面页面
默认的username为user,password打印在控制台中。当然了,同学们显示的肯定和我的不一样。
在浏览器中输入账号和密码后会显示login.html页面内容。
3、修改默认配置
1.修改默认密码
Security默认用户是user,密码是通过UUID随机生成。添加这些配置项,
UserDetailsServiceAutoConfiguration会基于配置信息在内存中创建一个用户user,如果没有配置,
UserDetailsServiceAutoConfiguration会自动在内存中创建一个密码用UUID随机生成的user用户。 通过修改application.properties(application.yml)
spring:
security:
user:
name: admin
password: admin
2.自定义登录页面
虽然Spring Security给我们提供了登录页面,但是对于实际项目中,大多喜欢使用自己的登录页面。所 以Spring Security中不仅仅提供了登录页面,还支持用户自定义登录页面。实现过程也比较简单,只需 要修改配置类即可。 说明:在上面代码基础上进行修改
1.添加thymeleaf的依赖
2.编写登录页面
在resources下新建templates文件夹。其中fail.html和success.html都只有一句话,分别是:“登录失 败”和“登录成功” login.html
3.编写控制器
新建一个IndexController
三个方法都是只有显示页面的功能。因为Thymeleaf页面必须通过控制器显示。如果示例代码是拿纯
HTMl静态页面演示,是不需要写这些控制器。
org.springframework.boot
spring-boot-starter-thymeleaf
lang="en">
charset="UTF-8">
action="/login" method="post">
用户名: type="text" name="username"/>
密码: type="password" name="password"/>
type="submit" value="提交"/>
@Controller
public class IndexController {
4.创建SecurityConfig配置类
在以往Spring Security的教程中我们自定义配置都是声明一个配置类
WebSecurityConfigurerAdapter ,然后覆写( @Override )对应的几个方法就行了。 然而这一切在Spring Security 5.4开始就得到了改变,从Spring Security 5.4 起我们不需要继承
WebSecurityConfigurerAdapter 就可以配置 HttpSecurity 了
@RequestMapping("/") public String showLogin() { return "login"; } @RequestMapping("/success") public String success() { return "success"; } @RequestMapping("/fail") public String fail() { return "fail"; } } /**
* SpringSecurity的配置
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) public class OldSecurityConfig extends WebSecurityConfigurerAdapter { }
@Configuration
public class SecurityConfig { @Bean
SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { httpSecurity.formLogin() // 哪个URL为登录页面
.loginPage("/") // 当发现什么URL时执行登录逻辑
.loginProcessingUrl("/login") // 登录成功页
.successForwardUrl("/success") // 登录失败页
.failureForwardUrl("/fail"); // 设置URL的授权问题 多个条件取交集
httpSecurity.authorizeRequests() // 匹配 / 控制器 permitAll() 不需要被认证就可以访问
.antMatchers("/").permitAll() // anyRequest() 所有请求 authenticated() 必须被认证
4、数据库访问方式
创建表并插入默认数据
创建用户对象
创建相应的mapper
.anyRequest().authenticated(); // 关闭csrf
httpSecurity.csrf().disable(); return httpSecurity.build(); } }
-- ---------------------------- -- Table structure for ums_admin -- ----------------------------
DROP TABLE IF EXISTS `ums_admin`;
CREATE TABLE `ums_admin` (
`id` bigint(20) NOT NULL AUTO_INCREMENT, `username` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT
NULL, `password` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT
NULL, PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '后台用户表' ROW_FORMAT = Dynamic;
-- ---------------------------- -- Records of ums_admin -- ----------------------------
INSERT INTO `ums_admin` VALUES (1, 'root',
'$2a$10$IXM8dvRox2Po40xNyvLJW.Txc3Ia9TOutQgKm0mk20l1T/azhiypa');
@Data @TableName("ums_admin")
public class UmsAdmin implements Serializable { private static final long serialVersionUID = 1L; @TableId(value = "id", type = IdType.AUTO) private Long id; private String username; private String password; }
public interface UmsAdminMapper extends BaseMapper<UmsAdmin> { }
创建serviceImpl实现UserDetailsService
这边我们用的是mybatis-plus,这部分不是今天的重点,这里我就不赘述了
创建配置文件CommonSecurityConfig
@Service @Log4j2
public class UmsAdminServiceImpl implements UserDetailsService { @Autowired
private UmsAdminMapper umsAdminMapper; @Override
public UserDetails loadUserByUsername(String username) { //获取用户信息
UmsAdmin admin = getAdminByUsername(username); if (admin == null) { throw new UsernameNotFoundException("用户名或密码错误"); } return new User(username, admin.getPassword(),
AuthorityUtils.commaSeparatedStringToAuthorityList("admin")); } /**
* 根据用户名获取后台管理员
*
* @param username
* @return
*/
public UmsAdmin getAdminByUsername(String username) { QueryWrapper<UmsAdmin> wrapper = new QueryWrapper<>(); wrapper.lambda().eq(UmsAdmin::getUsername, username); List<UmsAdmin> adminList = umsAdminMapper.selectList(wrapper); if (adminList != null && adminList.size() > 0) { UmsAdmin admin = adminList.get(0); return admin; } return null; } }
@Configuration
public class CommonSecurityConfig { // PasswordEncoder:SpringSecurity定义的用于对密码进行编码及比对的接口,目前使用的是
BCryptPasswordEncoder;
@Bean
public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
5、测试效果
在浏览器输入:http://localhost:8080显示登录页面。输入:账号:root,密码:root后会显示“登录成 功