1.正文
- 认证授权的概述
- 什么是SpringSecurity
- 如何使用springSecurity安全框架
2.认证授权的概述
1.1 什么是认证
进入移动互联网时代,大家每天都在刷手机,常用的软件有微信、支付宝、头条,抖音等,下边拿微信来举例子说明认证相关的基本概念,在初次使用微信前需要注册成为微信用户,然后输入账号和密码即可登录微信,==输入账号和密码登录微信的过程就是认证。
1.1.1系统为什么要认证?
认证是为了保护系统的隐私数据与资源,用户的身份合法,方可访问该系统的资源。
认证︰用户认证就是判断一个用户的身份是否合法的过程,用户去访问系统资源时系统要求验证用户的身份信息,身份合法 方可继续访问,不合法则拒绝访问。常见的用户身份认证方式有:用户名密码登录,二维码登录,手机短信登录,指纹认证等方式。
1.2 什么是会话
用户认证通过后,为了避免用户的每次操作都进行认证可将用户的信息保证在会话中。会话就是系统为了保持当前用户的登录状态所提供的机制,常见的有基于session方式、基于token方式等。
1.2.1 基于session的认证
它的交互流程是,用户认证成功后,在服务端生成用户相关的数据保存在session(当前会话)中,发给客户端的sesssion_id存放到 cookie中,这样用户客户端请求时带上 session_id 就可以验证服务器端是否存在 session 数据,以此完成用户的合法校验,当用户退出系统或session过期销毁时,客户端的session_id 也就无效了。
1.2.2 基于Token的认证
它的交互流程是,用户认证成功后,服务端生成一个token【令牌】[唯一字符串]【uuid,jwt】发给客户端,客户端可以放到 cookie 或sessionStorage等存储中,每次请求时带上token,服务端收到token通过验证后即可确认用户身份。
基于session的认证方式由servlet规范定制,服务端要存储session信息需要占用内存资源,客户端需要支持cookie;基于token的方式则一般不需要服务端存储token,并且不限制客户端的存储方式cookie sessionStorage LocalStorage Vuex。如今移动互联网时代更多类型的客户端[pC ,android,IOS,]需要接入系统,系统多是采用前后端分离的架构进行实现,所以基于token的方式更适合。
使用前后端分离或后台使用了集群---一定采用token模式。
传统的项目前端和后端都在一个工程下---基于session模式。
1.3 什么是授权
还拿微信来举例子,微信登录成功后用户即可使用微信的功能,比如,发红包、发朋友圈、添加好友等,没有绑定银行卡的用户是无法发送红包的,绑定银行卡的用户才可以发红包,发红包功能、发朋友圈功能都是微信的资源即功能资源,用户拥有发红包功能的==权限==才可以正常使用发送红包==功能==,拥有发朋友圈功能的权限才可以便用发朋友圈功能,这个根据用户的权限来控制用户使用资源的过程就是授权。
权限【权限表】----资源【接口】
1.3.1 为什么要授权
认证是为了保证用户身份的合法性,授权则是为了更细粒度的对隐私数据进行划分,==授权是在认证通过后发生的==,控制不同的用户能够访问不同的资源。
授权:授权是用户认证通过根据用户的权限来控制用户访问资源的过程,拥有资源的访问权限则正常访问,没有权限则拒绝访问。
认证授权的框架:
[1]shiro 轻量级的认证授权 它可以整合任意框架 它支持javase和javaee
[2]springsecurity 重量级的认证授权框架。它只能和spring整合,只支持javaee web框架。
spring非常麻烦,但是现在和springboot整合就很简单了。
3.什么是spring security?
Spring Security是一个能够为基于Spring的企业应用系统提供==声明式的安全访问控制解决方案的安全框架==。它提供了一组可以在Sprirg应用上下文中配置的Bean,充分利用了Spring IoC [],DI(控制反转Inversion of Control ,DI:Dependency Injection依赖主入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
以上解释来源于百度白科。可以一句话来概括,SpringSecurity 是一个安全框架。可以帮我们完成认证,密码加密,授权,rememberme的功能。
4. 快速入门springsecurity
基于内存的数据。
4.1 引入springsecurity的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
4.2创建接口资源
@RestController
public class HelloController {
@GetMapping("/hhh")
public String hello(){
return "hello";
}
4.3 在浏览器进行访问
在浏览器输入localhost:8080/hhh地址后,会被安全框架拦截然后跳转到框架默认的登录页面(过程会很慢,后续我们自定义登录页面就可以了)
用户名为user,密码在日志里面。如下图
登录成功后会跳转到想要的页面
5.定义多用户--基于内存
5.1 配置修改
package com.yh.springsecurity.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* @author :Stu HY
* @date :Created in 2024/7/28 9:10
* @description:配置
* @modified By:
* @version: 1.0
*/
@Configuration
public class Myonfig extends WebSecurityConfigurerAdapter {
/**
* 创建一个BCryptPasswordEncoder实例,用于加密和验证用户密码。
*
* 使用BCrypt算法对用户密码进行加密,提高了密码的安全性。BCrypt是一种基于口令的加密算法,
* 它通过使用随机盐值对密码进行散列,使得相同的密码经过加密后得到不同的结果,增加了密码的抗暴力破解能力。
*
* @return 返回一个新的BCryptPasswordEncoder实例。
*/
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
/**
* 配置AuthenticationManagerBuilder以进行内存中的认证管理。
* 这种配置方式主要用于在应用启动时静态定义用户账户及其权限。
*
* @param auth AuthenticationManagerBuilder的实例,用于配置认证策略。
* @throws Exception 如果配置过程中出现错误,将抛出异常。
*/
public void configure(AuthenticationManagerBuilder auth) throws Exception{
// 使用内存中的认证方式,并配置第一个用户
auth
.inMemoryAuthentication()
.withUser("aaa")
.password(passwordEncoder().encode("123456")) // 对密码进行编码
.roles("admin") // 指定用户角色
.authorities("admin:select","admin:insert","admin:delete") // 指定用户的权限
.and() // 连接下一个用户配置
// 配置第二个用户
.withUser("bbb")
.password(passwordEncoder().encode("123456")) // 对密码进行编码
.roles("user") // 指定用户角色
.authorities("user:select","user:insert"); // 指定用户的权限
}
/**
* 配置Spring Security以定制HTTP安全设置。
* 此方法定义了应用程序的登录页面、登录处理URL、成功登录后重定向的URL,
* 并配置所有这些路径都是公开的,不需要认证。
* 同时,禁用了CSRF保护以允许跨域请求。
* 最后,配置任何其他请求都需要经过认证才能访问。
*
* @param http Spring Security的HttpSecurity对象,用于配置安全规则。
* @throws Exception 如果配置过程中出现错误。
*/
public void configure(HttpSecurity http) throws Exception{
// 配置表单登录,指定登录页面、处理登录请求的URL、成功登录后重定向的URL,并允许所有这些请求无需认证。
http.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/login")
.successForwardUrl("/cg")
.permitAll(); // 上述所有请求路径无需认证
// 禁用CSRF保护,以允许跨域请求。
http.csrf().disable(); // 关闭csrf 禁用跨域伪造请求的过滤器
// 配置所有其他请求都需要经过认证才能访问。
// 除了上述请求 其他请求都需要认证
http.authorizeRequests().anyRequest().authenticated();
}
}
5.2 controller层实现
@Controller
public class LoginController {
@PostMapping("/cg")
public String index() {
// 重定向到首页
return "redirect:/success.html";
}
}
5.3 访问resource下的static资源
6.密码加密器
public class Test1 {
/**
* 主函数,用于演示BCryptPasswordEncoder的使用。
* BCryptPasswordEncoder是一个密码编码器,用于对用户密码进行安全的加密处理。
* 它使用BCrypt算法,该算法是一种经过时间考验的加密算法,为密码提供较强的保护。
*/
public static void main(String[] args) {
// 创建BCryptPasswordEncoder实例用于密码加密
PasswordEncoder passwordEncoder=new BCryptPasswordEncoder();
// 对明文密码"123456"进行加密,加密过程是不可逆的
// 用于加密
String encode = passwordEncoder.encode("123456");
// 再次对相同的明文密码进行加密,由于BCrypt算法的随机性,每次加密结果可能不同
String encode2 = passwordEncoder.encode("123456");
// 再次加密相同的明文密码,验证加密的非确定性
String encode3 = passwordEncoder.encode("123456");
// 打印加密后的密码,这些密码看起来是随机的,且不可逆向得到明文密码
System.out.println(encode);
System.out.println(encode2);
System.out.println(encode3);
// 验证明文密码"123456"是否与之前加密的密码encode2匹配
// 安全.
boolean matches = passwordEncoder.matches("123456", encode2);
// 打印验证结果,如果matches为true,则说明加密和解密过程是正确的
System.out.println("是否密码正确:"+matches);
}
}
7. 获取当前用户的信息
// springsecurity默认把当前用户的信息保存SecurityContext上下文中.
@GetMapping("/info")
public Authentication info(){
SecurityContext securityContext = SecurityContextHolder.getContext();
//把用户得到信息封装到Authontication类中--用户名---角色以及权限---状态[]
Authentication authentication = securityContext.getAuthentication();
UserDetails principal = (UserDetails) authentication.getPrincipal();
for (int i = 0; i < principal.getAuthorities().size(); i++) {
System.out.println(principal.getAuthorities().toArray()[i]);
}
return authentication;
}