![6ee20fb7c52b5234bb200f95f1c2b79c.png](https://img-blog.csdnimg.cn/img_convert/6ee20fb7c52b5234bb200f95f1c2b79c.png)
1.前言
上一篇文章介绍了如何用MyBatis实现后端数据库操作:Alex Wang:全栈开发踩坑之路4-用MyBatis实现服务,本文介绍如何使用Spring Security实现登录。
本后端项目的Github地址(撰写中):
apkkids/mymis_endgithub.com2.登录验证原理
对于一个网站后台来说,登录验证的原理应该是非常直白的。用户在前端页面输入用户名密码,后台获取用户名密码后,在数据库中查找用户名密码,然后进行比较操作,如果匹配成功则允许登录,否则报错。
登录成功后,不同的用户应该拥有不同的角色,不同的角色可以访问不同的网址;若访问该角色无权访问的网址,则也会报错,如下图所示:
![c85d2ebf43bf13b6ba60edf21781b48e.png](https://img-blog.csdnimg.cn/img_convert/c85d2ebf43bf13b6ba60edf21781b48e.png)
如果不用任何安全框架,原始时代的程序员会这样来设计实现以上功能:
1.后端服务器会创建一个对象来保存用户名密码等凭据;
2.访问数据库,进行查询和比对,给出登录是否成功的结果;
3.设计数据库的用户表、角色表、资源表以及关联表;
4.用户登录成功后,从数据库中获取用户的角色列表;
5.当用户要访问一个资源时,从数据库中获取该资源的角色列表;
6.比对用户角色和资源角色,给出是否能够授权访问的结果。
以上做法并无不可,只不过登录、鉴权等功能每个MIS系统都需要,因此可以抽象出安全框架来更加便捷的实现这些功能,例如Spring Security框架。
3.使用Spring Security原理简介
平心而论,使用Spring Security并不比直接实现以上功能更简单,加上学习成本,初次使用更觉复杂。但安全框架一旦掌握,就可方便快捷的用于各种安全控制功能中,且它已经与SpringBoot紧密耦合,一旦熟练掌握,受益匪浅。
以下是我自己画的Spring Security原理图,仅仅包含我自己理解的部分:
![c3a055380afb24424f6bac583c4eb419.png](https://img-blog.csdnimg.cn/img_convert/c3a055380afb24424f6bac583c4eb419.png)
对于Spring Security的理解和使用,可以顺着此图一路看下来。
1)前端框架中输入的用户名密码到达后端后,会被BCryptPasswordEncoder加密,原始密码会被丢弃,得到一个用于校验的值。这样即使数据库泄露,也无从得知用户的原始密码;
2)用户名密码会被存入一个凭据类Authentication中;
3)ProviderManager会维护一条验证链,凭据会从这条链中穿过,依次进行验证;只要有任何一个AuthenticationProvider验证通过,则视为验证成功;
4)由于要使用数据库中的数据进行验证,我们自定义了一个DaoAuthenticationProvider,这个类不用我们自己写,而是通过实现以下两个接口来间接使用它;
5)实现UserDetails接口,它是用户类的代表,它的getAuthorities方法可以得到角色列表;
6)实现数据访问服务接口UserDetailsService,它会从数据库中查询用户密码;
7)验证成功后的Authentication会存入SecurityContext中,可以随时被使用;
8)当登录的用户要访问某个首保护的资源时,访问决策管理员类AccessDecisionManager会进行决策;
9)决策时要使用到安全元数据类FilterInvocationSecurityMetadataSource中的getAttributes方法,它返回资源所需的角色列表。把它与SecurityContext中Authentication的角色列表进行比对,就能知道是否可以访问;
10)以上的功能由Web安全配置类WebSecurityConfigurerAdapter进行配置;
11)以上所需的数据库访问功能可以由MyBatis提供,所需要的数据库表基本上就是图中列出的5张表。
4.代码实现
代码在Github中,为了实现登录验证所涉及的类包括:
- 用户类Admin、AdminMapper;
- 角色类Role、RoleMapper;
- 资源类Resource、ResourceMapper;
- 服务类AdminService;
- 配置类MainWebSecurityConfigurer;
- 鉴权相关类MySecurityMetadataSource、MyAccessDecisionManager和MyAccessDeniedHandler;
- 用来测试的控制类TestSecurityController。
运行代码后,可以进行如下测试:
该Controller是为了测试登录鉴权功能而提供的,它包含一些用于测试的网址* 用户 角色* admin ROLE_admin* test1 ROLE_manager* test2 ROLE_personnel** 资源 所需角色* /test/admin ROLE_admin* /test/manager ROLE_manager* /test/personnel ROLE_personnel** 测试过程* admin访问三个资源,均可* test1访问三个资源,只有第二个可以* test2访问三个资源,只有第三个可以
测试的结果如:
使用test2登录/test/manager网址:
{"status":500,"msg":"你没有访问FilterInvocation: URL: /test/manager的权限!","obj":null}
使用test2登录/test/personnel网址:
url地址:/test/personnel 用户名:test2 权限: ROLE_personnel
5.更加详细的例子
关于使用Spring Security进行验证和鉴权,我还写了单独的一个系列,可以看这里:
第一篇:Spring Security零基础入门之一。
第二篇:Spring Security零基础入门之二~验证
第三篇:Spring Security零基础入门之三~使用数据库进行验证
第四篇:Spring Security零基础入门之四~鉴权
这个系列还有一个独立的github项目:
apkkids/spring_security_examgithub.com![600f6a94aa5f0f85d635978b0f015c13.png](https://img-blog.csdnimg.cn/img_convert/600f6a94aa5f0f85d635978b0f015c13.png)
6.小结
为了实现项目的登录和权限管理,使用了Spring Security,了解了它的一些相关知识,并编写了测试代码,使得不使用前端也可以进行测试。后续将开始前端项目的设计实现。