一:认证授权
什么是认证授权:
认证:
在互联网中,我们每天都会使用到各种各样的APP和网站,在使用过程中通常还会遇到需要注册登录的情况,输入你的用户名和密码才能正常使用,也就是说成为这个应用的合法身份才可以访问应用的资源,这个过程就是认证。认证是为了保护系统的隐私数据与资源,用户的身份合法方可访问该系统的资源。
当然认证的方式有很多,常见的账号密码登录,手机验证码登录,指纹登录,刷脸登录等等。
简单说: 认证就是让系统知道我们是谁。
授权:
认证是为了保护身份的合法性,授权则是为了更细粒度的对数据进行划分,授权是在认证通过的前提下发生的。控制不同的用户能够访问不同的资源。
二:权限数据模型
授权过程中,我们需要知道如何对用户访问的资源进行控制,需要了解一些简单的授权数据模型。授权可以非常简单的理解成谁(Who)对什么资源(What)进行怎么样(How)的操作。
名词 | 含义 | 备注 |
Who | 主体(Subject) | 一般指用户,也可以是应用程序 |
What | 资源(Resource) | 例如商品信息,订单信息,页面按钮或程序中的接口等信息 |
How | 权限(Permission) | 规定了用户或程序对资源操作的许可。例如普通用户只能查看订单,管理员可修改或删除订单,这是因为普通用户和管理员用户对订单资源的操作权限不一样。 |
关系图概述:
RBAC权限数据模型
2.1基于角色访问权限控制
RBAC基于角色的访问控制(Role-Based Access Control)是按角色进行授权,比如:主体的角色为总经理可以查询企业运营报表,查询员工工资信息等,访问控制流程如下:
基于以上模型可以将其转换为相关代码如下:
if(主体.hasRole("总经理角色标识")){ //查询工资 }else{ //权限不足 }
如果上图中查询工资所需要的角色变化为总经理和部门经理,此时就需要修改判断逻辑为“判断用户的角色是否是 总经理或部门经理”,修改代码如下:
if(主体.hasRole("总经理角色标识") || 主体.hasRole("部门经理角色标识")){ //查询工资 }else{ //权限不足 }
2.2基于资源访问权限控制
RBAC基于资源的访问控制(Resource-Based Access Control)是按资源(或权限)进行授权。
基于第二种方式以上的需求就变成了如下:
if(Subject.hasPermission("查询员工工资的权限标识")){ // 查询员工工资 }
因此,使用基于资源访问权限控制的优点如下:
系统设计时定义好查询工资的权限标识,即使查询工资所需要的角色变化为总经理和部门经理也不需要修授权代码,系统可扩展性强。
常见的认证方式
1.Cookie-Session
该种认证机制的总体流程如下:
但是该种认证方式也有以下弊端:
- 只能在 web 场景下使用,如果是 APP 中,不能使用 cookie 的情况下就不能用了;
- 即使能在 web 场景下使用,也要考虑跨域问题,因为 cookie 不能跨域;(域名或者ip一致,端口号一致,协议要一致)
- cookie 存在 CSRF(跨站请求伪造)的风险;
- 如果是分布式服务,需要考虑 Session 同步(同步)问题;
- session-cookie机制是有状态的方式(后端保存主题的用户信息-浪费后端服务器内存)
2.jwt令牌无状态认证
JSON Web Token(JWT-字符串)是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。
该种认证方式的总体流程如下:
使用第二种方式的优点:
A. 使用 json 作为数据传输,有广泛的通用型,并且体积小,便于传输;
B. 不需要在服务器端保存相关信息,节省内存资源的开销;
C. jwt 载荷部分可以存储业务相关的信息(非敏感的),例如用户信息、角色等;
三:JWT
JSON Web Token(JWT)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。该token被设计为紧凑且安全的,特别适用于前后端无状态认证的场景。
1.JWT的组成
- 部(Header)(非敏感)
- 头部用于描述关于该JWT的最基本的信息,例如数据类型以及签名所用的算法等,本质是一个JSON格式对象;
- 举例说明
- {"typ":"JWT","alg":"HS256"} 解释:在头部指明了签名算法是HS256算法,整个JSON对象被BASE64编码形成JWT头部字符串信息;
- BASE64编码详见:在线加密解密,编码后的字符串:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
- 值得注意的是BASE64不是加密算法,可进行正向编码和反向解码处
- 载荷(playload)(非敏感数据)
- 载荷就是存放有效信息的地方,该部分的信息是可以自定义的;
- 载荷payload格式:{"sub":"1234567890","name":"John Doe","admin":true}
- 载荷相关的JSON对象经过BASE64编码形成JWT第二部分:eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG7CoERvZSIsImFkbWluIjp0cnVlfQ==
- 签证(signature)
- jwt的第三部分是一个签证信息,这个签证信息由三部分组成:签名算法( header (base64后的).payload (base64后的) . secret )
- 这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret秘钥组合加密,然后就构成了jwt的第三部分:TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
最后将这三部分用●连接成一个完整的字符串,构成了最终的jwt:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG7CoERvZSIsImFkbWluIjp0cnVlfQ==.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
2.JWT的使用
1.先导入依赖包:
<dependencies> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> </dependencies>
2.生成JWT令牌
@Test public void testGenerate(){ String compact = Jwts.builder() .setId(UUID.randomUUID().toString())//设置唯一标识 .setSubject("JRZS") //设置主题 .claim("name", "nineclock") //自定义信息 .claim("age", 88) //自定义信息 .setExpiration(new Date()) //设置过期时间 .setIssuedAt(new Date()) //令牌签发时间 .signWith(SignatureAlgorithm.HS256, "itheima")//签名算法, 秘钥 .compact(); System.out.println(compact); }
四:SpringSecurity
- Spring Security是基于Spring的安全框架,提供了包含认证和授权的落地方案;
- Spring Security底层充分利用了Spring IOC和AOP功能,为企业应用系统提供了声明式安全访问控制解决方案;
- SpringSecurity可在Web请求级别和方法调用级别处理身份认证和授权,为应用系统提供声明式的安全访问控制功能;
五:总结
Spring Security具有以下几个优点:
1. 综合性:Spring Security提供了一套完整的安全解决方案,包括身份验证、授权、会话管理等功能,能够满足大多数应用的安全需求。
2. 灵活性:Spring Security提供了丰富的配置选项和扩展点,可以根据具体需求进行定制和扩展。开发人员可以根据自己的业务逻辑和安全需求,自定义认证和授权规则,以及会话管理策略。
3. 集成性:Spring Security可以与各种其他框架和技术进行集成,如Spring框架、Spring Boot、OAuth2、LDAP、CAS等。它可以无缝与现有的应用程序和基础设施集成,使开发者可以更方便地使用和扩展安全功能。
4. 安全性:Spring Security提供了多种密码编码算法和安全策略,能够确保用户密码的安全存储和传输。它还提供了安全事件和日志记录功能,方便进行安全审计和监控。
5. 社区支持:Spring Security是一个成熟且广泛使用的安全框架,具有庞大的开发者社区。开发者可以从社区中获取大量的学习资源、示例代码和解决方案,以及获得及时的技术支持。
综合来看,Spring Security是一个功能强大、灵活、易用且安全可靠的安全框架,能够满足大多数应用的安全需求,是开发企业级应用程序的首选安全解决方案。