引言
软件开发过程中都必须要有的一个功能,那就是认证与授权,经过大佬们的不断更新迭代,使得如今实现认证与授权功能变得相对简单,也许你并不能真正的接触到认证与授权这一功能,除非你接触的项目是从0到1的,即便是这样的项目,认证与授权这一块依旧是系统架构师负责的,正因如此,我们更应该去学习认证与授权,扩展自己的知识面,这样才能在未来成为别人眼中的大佬,那么什么是认证与授权呢,简单讲就是在进入系统前需要进行账号登录,登录时系统根据用户输入的账号密码进行验证,验证通过后返回该用户所拥有的操作权限,本文会从Java认证与授权的发展历程和现在使用最多的标准和框架来讲述
发展历程
Java程序中的认证与授权机制经历了从简单到复杂、从单一到多样化的历史进程
早期
校验用户名和密码,但随着网络攻击手段的不断迭代,这种方式就暴露除了缺陷
JavaSE时期
JavaSE平台提供了更加灵活和安全的认证与授权解决方案,Java Authentication and AuthorizationService(标准认证与授权API),允许开发者在运行时动态配置应用程序的安全策略,支持多种认证方式,
JAVAEE时期
Java应用开始支持更加复杂的认证与授权机制
Spring Security时期
随着Spring框架的流行,其生态中的Spring Security逐渐成为Java应用中最受欢迎的认证与授权框架之一,它提供了全面的认证与授权功能,支持多种认证与机制,还提供了基于角色的访问控制(RBAC)、基于属性的访问控制(ABAC)以及基于策略的访问控制(PBAC)等,使得开发者能够更加方便地实现复杂地访问控制逻辑
OAuth2与OpenConnect
随着第三方应用和服务的兴起,OAuth2和OpenID Connect逐渐成为Java应用中处理第三方认证与授权的重要标准。OAuth2运行第三方应用获取用户在HTTP服务上的部分信息,而无需获取用户的密码和访问所有数据。OpenID Connect则是一种基于OAuth2的身份验证协议,它允许用户通过第三方身份提供者进行身份验证,并且获取有关用户的身份信息。Java中,Spring Security OAuth项目为开发者提供了实现OAuth2和OpenID Connect认证与授权的必要API和工具,这使得Java应用能够更加方便地集成第三方认证服务,实现用户在不同应用程序间地无缝登录和权限管理
现在
经过长时间地发展,现在Java应用中的认证与授权机制已经变得更加复杂和多样化。除了传统的校验用户名/密码和基于角色的访问控制等外,还涌现出了许多新的认证方式和授权策略,如基于令牌的身份验证(JWT),多因素认证(MFA)等,这些都使得Java应用的安全保护能力更加灵活和强大。并且随着云计算、微服务和容器技术的普及,Java应用中的认证与授权机制也开始向分布式、可扩展和自动化的方向发展,如,Spring Cloud Security,使得开发者可以更加方便地实现微服务之间地认证与授权集成,以及基于策略的自动化访问控制
随着技术的不断进步和应用场景的不断拓展,Java应用中的认证与授权机制将继续向更加安全、灵活和智能化的方向发展
使用最多的标准和框架
标准
OAuth 2.0
开放标准,允许用户提供一个令牌,而不是用户名和密码,给第三方应用以访问它们其他服务上存储的私密资源,被广泛用于API授权,使得第三方应用能够安全的访问用户资源,通常结合Spring Security OAuth2等扩展库使用,实现授权服务器的搭建和客户端的授权请求
OpenID Connect
OAuth 2.0的扩展层,它允许用户通过单一的身份标识进行身份验证,并获取关于该用户的信息,在OAuth 2.0的认证流程基础上新增了用户信息的获取功能,广泛应用在Java应用中,特别时单点登录功能
JWT
一种用于双方安全传输信息的简洁的、URL安全的令牌标准,基于JSON对象,通过数字签名的方式进行验证和确保信息的安全性,通常与Spring Security等安全框架结合使用,用于生成、解析和校验令牌,广泛应用在分布式系统实现单点登录等功能
框架
Spring Security
Spring生态中的一个安全框架,提供了全面的安全性解决方案,支持认证、授权、加密、会话管理等安全功能,并且与Spring生态系统中的其他组件无缝集成,其中认证方式有多种:表单登录、HTTP Basic认证、OAuth2等,并且支持基于角色的访问控制和基于属性的访问控制
Apache Shiro
一个轻量级的Java安全框架,提供了身份验证、授权、加密和会话管理功能,还提供了丰富的配置选项和文档支持,适用于小型项目或对性能要求较高的场景
Sa-Token
简介
最近几年出现的轻量级Java权限认证框架,主要解决:登录认证、权限认证、单点登录、OAuth 2.0、分布式Session会话、微服务网关鉴权等一系列权限相关问题,它的成功得益于简单且直观的API设计、模块化设计易于集成、对性能进行优化同时提供高效的加密算法来提高安全性、提供了丰富的扩展接口等,被广泛应用于Web应用中,因为小编最近有使用,感觉不错,推荐给大家
集成与使用
以微服务为例讲解两种不同环境的集成,网关采用Spring WebFlux环境,其他服务采用SpringBoot环境
Spring WebFlux环境
Maven依赖
<!-- Sa-Token 权限认证(Reactor响应式集成) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-reactor-spring-boot-starter</artifactId>
<version>1.39.0</version>
</dependency>
配置全局过滤器
/**
* [Sa-Token 权限认证] 全局配置类
* @author muze
*/
@Configuration
public class SaTokenConfig {
/**
* 注册 [Sa-Token全局过滤器]
*/
@Bean
public SaReactorFilter getSaReactorFilter() {
return new SaReactorFilter()
// 指定 [拦截路由]
.addInclude("/**")
// 指定 [放行路由]
.addExclude("/login")
// 指定[认证函数]: 每次请求执行登录校验
.setAuth(obj -> StpUtil.checkLogin())
// 指定[异常处理函数]:每次[认证函数]发生异常时执行此函数
.setError(e -> SaResult.error(e.getMessage()));
}
}
跨域解决方式
一、在全局过滤器中链式调用如下方法
// 前置函数:在每次认证函数之前执行
.setBeforeAuth(obj -> {
SaHolder.getResponse()
// ---------- 设置跨域响应头 ----------
// 允许指定域访问跨域资源
.setHeader("Access-Control-Allow-Origin", "*")
// 允许所有请求方式
.setHeader("Access-Control-Allow-Methods", "*")
// 允许的header参数
.setHeader("Access-Control-Allow-Headers", "*")
// 有效时间
.setHeader("Access-Control-Max-Age", "3600");
// 如果是预检请求,则立即返回到前端
SaRouter.match(SaHttpMethod.OPTIONS)
.free(r -> System.out.println("--------OPTIONS预检请求,不做处理"))
.back();
});
二、自定义WebFlux配置
/**
* 自定义WebFlux配置
* 实现WebFlux接口
* 覆写配置 CORS(跨源资源共享)策略方法
* @author muze
*/
@Configuration
public class CustomWebFluxConfig implements WebFluxConfigurer {
/**
* 配置 CORS(跨源资源共享)策略
* @param corsRegistry 配置 CORS(跨源资源共享)策略的注册器
*/
@Override
public void addCorsMappings(CorsRegistry corsRegistry) {
corsRegistry.addMapping("/**") // 允许跨域的路径
.allowedOrigins("*") // 允许跨域请求的域名
.allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的请求方法
.allowedHeaders("*") // 允许的请求头
.allowCredentials(true); // 允许证书(cookies)
}
}
SpringBoot环境
Maven依赖
<!-- Sa-Token 权限认证 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.39.0</version>
</dependency>
配置yml文件
############## Sa-Token 配置 ##############
sa-token:
# token 名称(同时也是 cookie 名称)
token-name: satoken
# token 有效期(单位:秒) 默认30天,-1 代表永久有效
timeout: 2592000
# token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
active-timeout: -1
# 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
is-concurrent: true
# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
is-share: true
# token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
token-style: uuid
# 是否输出操作日志
is-log: true
集成好后我们只需要在登录业务中调用Sa-Token提供的登录API:login,传入用户主键即可
/**
* 用户控制层
* @author muze
*/
@RestController
public class UserController {
/**
* 登录
* @param username 用户名
* @param password 密码
* @return 登录结果
*/
@PostMapping("/login")
public SaResult login(String username, String password) {
// TODO:校验用户名和密码
// 正确则调用login传入用户主键,返回登录结果
StpUtil.login(1);
return SaResult.ok("登录成功");
}
}
这样就登录成功了,Sa-Token会生成一个令牌并保存到浏览器的cookie中,后续请求前端需要携带cookie中的令牌访问后端接口,网关会在全局过滤器中调用checkLogin去校验是否已经登录
如果我们的项目没有网关,那么我们就需要配置跨域和拦截器,每次请求在拦截器中进行登录验证
/**
* 跨域配置
* @author muze
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
/**
* 添加跨域映射
* @param registry Cross-Origin Resource Sharing Registry:跨域资源共享登记
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
// 允许跨域访问的URL模式
registry.addMapping("/**")
// 允许跨域请求的域名(ip:port)
.allowedOrigins("*")
// 允许的方法
.allowedMethods("GET", "POST", "PUT", "DELETE")
// 允许的头信息
.allowedHeaders("*")
// 是否允许发送Cookie
.allowCredentials(false);
}
/**
* 添加拦截器
* @param interceptorRegistry 注册拦截器实体
*/
@Override
public void addInterceptors(InterceptorRegistry interceptorRegistry) {
//添加 Sa-Token 拦截器,校验规则为 登录校验 StpUtil.checkLogin()
interceptorRegistry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
// 添加校验路径
.addPathPatterns("/**")
// 排除校验路径
.excludePathPatterns("/login");
}
}
到这里,一个Java集成Sa-Token并完成一个简单的登录和登录验证就完成了,还有很多简单好用的API,详情请参考官方在线文档:Sa-Token
总结
当我们在职场中还接触不到认证与授权,但又希望了解并学习来提升自己和为未来做准备的话,可以进行自主学习,该篇文章就是小编的自主学习并使用的一些心得,希望能帮助到你们,感兴趣的朋友赶紧去试试吧,相信这篇文章能给你们一些帮助