JAVA技术交流QQ群:170933152

AuthenticationProvider

认证是由 AuthenticationManager 来管理的,但是真正进行认证的是 AuthenticationManager 中定义的 AuthenticationProvider。AuthenticationManager 中可以定义有多个 AuthenticationProvider。当我们使用 authentication-provider 元素来定义一个 AuthenticationProvider 时,如果没有指定对应关联的 AuthenticationProvider 对象,Spring Security 默认会使用 DaoAuthenticationProvider。DaoAuthenticationProvider 在进行认证的时候需要一个 UserDetailsService 来获取用户的信息 UserDetails,其中包括用户名、密码和所拥有的权限等。所以如果我们需要改变认证的方式,我们可以实现自己的 AuthenticationProvider;如果需要改变认证的用户信息来源,我们可以实现 UserDetailsService。

实现了自己的 AuthenticationProvider 之后,我们可以在配置文件中这样配置来使用我们自己的 AuthenticationProvider。其中 myAuthenticationProvider 就是我们自己的 AuthenticationProvider 实现类对应的 bean。

  1. <security:authentication-manager>

  2. <security:authentication-provider ref="myAuthenticationProvider"/>

  3. </security:authentication-manager>

实现了自己的 UserDetailsService 之后,我们可以在配置文件中这样配置来使用我们自己的 UserDetailsService。其中的 myUserDetailsService 就是我们自己的 UserDetailsService 实现类对应的 bean。

  1. <security:authentication-manager>

  2. <security:authentication-provider user-service-ref="myUserDetailsService"/>

  3. </security:authentication-manager>

用户信息从数据库获取

通常我们的用户信息都不会向第一节示例中那样简单的写在配置文件中,而是从其它存储位置获取,比如数据库。根据之前的介绍我们知道用户信息是通过 UserDetailsService 获取的,要从数据库获取用户信息,我们就需要实现自己的 UserDetailsService。幸运的是像这种常用的方式 Spring Security 已经为我们做了实现了。

使用 jdbc-user-service 获取

在 Spring Security 的命名空间中在 authentication-provider 下定义了一个 jdbc-user-service 元素,通过该元素我们可以定义一个从数据库获取 UserDetails 的 UserDetailsService。jdbc-user-service 需要接收一个数据源的引用。

  1. <security:authentication-manager>

  2. <security:authentication-provider>

  3. <security:jdbc-user-service data-source-ref="dataSource"/>

  4. </security:authentication-provider>

  5. </security:authentication-manager>

上述配置中 dataSource 是对应数据源配置的 bean 引用。使用此种方式需要我们的数据库拥有如下表和表结构。

这是因为默认情况下 jdbc-user-service 将使用 SQL 语句 “select username, password, enabled from users where username = ?” 来获取用户信息;使用 SQL 语句 “select username, authority from authorities where username = ?” 来获取用户对应的权限;使用 SQL 语句 “select g.id, g.group_name, ga.authority from groups g, group_members gm, group_authorities ga where gm.username = ? and g.id = ga.group_id and g.id = gm.group_id” 来获取用户所属组的权限。需要注意的是 jdbc-user-service 定义是不支持用户组权限的,所以使用 jdbc-user-service 时用户组相关表也是可以不定义的。如果需要使用用户组权限请使用 JdbcDaoImpl,这个在后文后讲到。

当然这只是默认配置及默认的表结构。如果我们的表名或者表结构跟 Spring Security 默认的不一样,我们可以通过以下几个属性来定义我们自己查询用户信息、用户权限和用户组权限的 SQL。

属性名 说明
users-by-username-query 指定查询用户信息的 SQL
authorities-by-username-query 指定查询用户权限的 SQL
group-authorities-by-username-query 指定查询用户组权限的 SQL

假设我们的用户表是 t_user,而不是默认的 users,则我们可以通过属性 users-by-username-query 来指定查询用户信息的时候是从用户表 t_user 查询。

  1. <security:authentication-manager>

  2. <security:authentication-provider>

  3. <security:jdbc-user-service

  4. data-source-ref="dataSource"

  5. users-by-username-query="select username, password, enabled from t_user where username = ?" />

  6. </security:authentication-provider>

  7. </security:authentication-manager>

role-prefix 属性

jdbc-user-service 还有一个属性 role-prefix 可以用来指定角色的前缀。这是什么意思呢?这表示我们从库里面查询出来的权限需要加上什么样的前缀。举个例子,假设我们库里面存放的权限都是 “USER”,而我们指定了某个 URL 的访问权限 access=”ROLEUSER”,显然这是不匹配的,Spring Security 不会给我们放行,通过指定 jdbc-user-service 的 role-prefix=”ROLE\” 之后就会满足了。当 role-prefix 的值为 “none” 时表示没有前缀,当然默认也是没有的。

直接使用 JdbcDaoImpl

JdbcDaoImpl 是 UserDetailsService 的一个实现。其用法和 jdbc-user-service 类似,只是我们需要把它定义为一个 bean,然后通过 authentication-provider 的 user-service-ref 进行引用。

  1. <security:authentication-manager>

  2. <security:authentication-provider user-service-ref="userDetailsService"/>

  3. </security:authentication-manager>

  4. <bean id="userDetailsService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">

  5. <property name="dataSource" ref="dataSource"/>

  6. </bean>

如你所见,JdbcDaoImpl 同样需要一个 dataSource 的引用。如果就是上面这样配置的话我们数据库表结构也需要是标准的表结构。当然,如果我们的表结构和标准的不一样,可以通过 usersByUsernameQuery、authoritiesByUsernameQuery 和 groupAuthoritiesByUsernameQuery 属性来指定对应的查询 SQL。

用户权限和用户组权限

JdbcDaoImpl 使用 enableAuthorities 和 enableGroups 两个属性来控制权限的启用。默认启用的是 enableAuthorities,即用户权限,而 enableGroups 默认是不启用的。如果需要启用用户组权限,需要指定 enableGroups 属性值为 true。当然这两种权限是可以同时启用的。需要注意的是使用 jdbc-user-service 定义的 UserDetailsService 是不支持用户组权限的,如果需要支持用户组权限的话需要我们使用 JdbcDaoImpl。

  1. <security:authentication-manager>

  2. <security:authentication-provider user-service-ref="userDetailsService"/>

  3. </security:authentication-manager>

  4. <bean id="userDetailsService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">

  5. <property name="dataSource" ref="dataSource"/>

  6. <property name="enableGroups" value="true"/>

  7. </bean>

PasswordEncoder

使用内置的 PasswordEncoder

通常我们保存的密码都不会像之前介绍的那样,保存的明文,而是加密之后的结果。为此,我们的 AuthenticationProvider 在做认证时也需要将传递的明文密码使用对应的算法加密后再与保存好的密码做比较。Spring Security 对这方面也有支持。通过在 authentication-provider 下定义一个 password-encoder 我们可以定义当前 AuthenticationProvider 需要在进行认证时需要使用的 password-encoder。password-encoder 是一个 PasswordEncoder 的实例,我们可以直接使用它,如:

  1. <security:authentication-manager>

  2. <security:authentication-provider user-service-ref="userDetailsService">

  3. <security:password-encoder hash="md5"/>

  4. </security:authentication-provider>

  5. </security:authentication-manager>

其属性 hash 表示我们将用来进行加密的哈希算法,系统已经为我们实现的有 plaintext、sha、sha-256、md4、md5、{sha} 和 {ssha}。它们对应的 PasswordEncoder 实现类如下:

加密算法 PasswordEncoder 实现类
plaintext PlaintextPasswordEncoder
sha ShaPasswordEncoder
sha-256 ShaPasswordEncoder,使用时new ShaPasswordEncoder(256)
md4 Md4PasswordEncoder
md5 Md5PasswordEncoder
{sha} LdapShaPasswordEncoder
{ssha} LdapShaPasswordEncoder

#### 使用 BASE64 编码加密后的密码 此外,使用 password-encoder 时我们还可以指定一个属性 base64,表示是否需要对加密后的密码使用 BASE64 进行编码,默认是 false。如果需要则设为 true。 ``` ``` #### 加密时使用 salt 加密时使用 salt 也是很常见的需求,Spring Security 内置的 password-encoder 也对它有支持。通过 password-encoder 元素下的子元素 salt-source,我们可以指定当前 PasswordEncoder 需要使用的 salt。这个 salt 可以是一个常量,也可以是当前 UserDetails 的某一个属性,还可以通过实现 SaltSource 接口实现自己的获取 salt 的逻辑,SaltSource 中只定义了如下一个方法。 ``` public Object getSalt(UserDetails user); ``` 下面来看几个使用 salt-source 的示例。 1.下面的配置将使用常量“abc”作为 salt。 ``` ``` 2.下面的配置将使用 UserDetails 的 username 作为 salt。 ``` ``` 3.下面的配置将使用自己实现的 SaltSource 获取 salt。其中 mySaltSource 就是 SaltSource 实现类对应的 bean 的引用。 ``` ``` 需要注意的是 AuthenticationProvider 进行认证时所使用的 PasswordEncoder,包括它们的算法和规则都应当与我们保存用户密码时是一致的。也就是说如果 AuthenticationProvider 使用 Md5PasswordEncoder 进行认证,我们在保存用户密码时也需要使用 Md5PasswordEncoder;如果 AuthenticationProvider 在认证时使用了 username 作为 salt,那么我们在保存用户密码时也需要使用 username 作为 salt。如: ``` Md5PasswordEncoder encoder = new Md5PasswordEncoder(); encoder.setEncodeHashAsBase64(true); System.out.println(encoder.encodePassword("user", "user")); ``` ### 使用自定义的 PasswordEncoder 除了通过 password-encoder 使用 Spring Security 已经为我们实现了的 PasswordEncoder 之外,我们也可以实现自己的 PasswordEncoder,然后通过 password-encoder 的 ref 属性关联到我们自己实现的 PasswordEncoder 对应的 bean 对象。 ``` ``` 在 Spring Security 内部定义有两种类型的 PasswordEncoder,分别是 org.springframework.security.authentication.encoding.PasswordEncoder 和 org.springframework.security.crypto.password.PasswordEncoder。直接通过 password-encoder 元素的 hash 属性指定使用内置的 PasswordEncoder 都是基于 org.springframework.security.authentication.encoding.PasswordEncoder 的实现,然而它现在已经被废弃了,Spring Security 推荐我们使用 org.springframework.security.crypto.password.PasswordEncoder,它的设计理念是为了使用随机生成的 salt。关于后者 Spring Security 也已经提供了几个实现类,更多信息请查看 Spring Security 的 API 文档。我们在通过 password-encoder 使用自定义的 PasswordEncoder 时两种 PasswordEncoder 的实现类都是支持的。

security工作笔记007---spring security自定义AuthenticationProvider,验证规则相关推荐

  1. security工作笔记006---oauth2(spring security)报错method_not_allowed(Request method 'GET' not supported)解决

    JAVA技术交流QQ群:170933152 最近做智慧城市项目,太恶心了...各种不会,个人负责权限验证中心服务,...唉,慢慢研究吧.. 报错信息 <MethodNotAllowed> ...

  2. SpringBoot + Spring Security 学习笔记(一)自定义基本使用及个性化登录配置

    官方文档参考,5.1.2 中文参考文档,4.1 中文参考文档,4.1 官方文档中文翻译与源码解读 SpringSecurity 核心功能: 认证(你是谁) 授权(你能干什么) 攻击防护(防止伪造身份) ...

  3. security工作笔记009---spring security BCryptPasswordEncoder加密解密,不错的随机盐,不错的加密解密方法

    JAVA技术交流QQ群:170933152 项目中用这个加密感觉不错啊,推荐: 1.先大体看看,了解一下 浅谈使用springsecurity中的BCryptPasswordEncoder方法对密码进 ...

  4. security工作笔记008---springBoot springCloud中的security配置全解

    JAVA技术交流QQ群:170933152 spring security是springboot支持的权限控制系统. security.basic.authorize-mode要使用权限控制模式. s ...

  5. 爆破专栏丨Spring Security系列教程之Spring Security的四种权限控制方式

    原创:一一哥 前言: 在前面的章节中,一一哥 已经给大家介绍了Spring Security的很多功能,在这些众多功能中,我们知道其核心功能其实就是认证+授权. 在前面我们分别基于内存模型.基于默认的 ...

  6. Spring Security系列教程解决Spring Security环境中的跨域问题

    原创:千锋一一哥 前言 上一章节中,一一哥 给各位讲解了同源策略和跨域问题,以及跨域问题的解决方案,在本篇文章中,我会带大家进行代码实现,看看在Spring Security环境中如何解决跨域问题. ...

  7. SpringSecurity学习笔记(三)自定义资源拦截规则以及登录界面跳转

    参考视频,编程不良人 由前面的学习可以知道,SS的默认的拦截规则很简单,我们在项目中实际使用的时候往往需要更加复杂的拦截规则,这个时候就需要自定义一些拦截规则. 自定义拦截规则 在我们的项目中,资源往 ...

  8. ElementUI中form表单组件自定义手机号验证规则

    <el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" ...

  9. security工作笔记004---.NET Web安全性-身份验证和授权(一)之Principal

    JAVA技术交流QQ群:170933152 1.概述 为了确保应用程序的安全,安全性有几个重要方面需要考虑.一是应用程序的用户,访问应用程序的是一个真正的用户,还是伪装成用户的某个人?如何确定这个用户 ...

最新文章

  1. [py][mx]django form验证-给db减压
  2. 【CentOS7配置】如何设置:启动后自动获取网络连接、配置固定IP
  3. 牛逼哄哄的 MQ 到底有啥用?
  4. 电子病历基本架构与数据标准
  5. 程序设计竞赛中常用的STL汇总
  6. Python 下的 lambda 算子
  7. Android入门:HttpClient介绍
  8. Linux下安装hbase
  9. 保留地址就是私有地址吗?
  10. 真无线蓝牙耳机的原理及其优缺点
  11. 文华财经指标公式,通达信指标加密破解
  12. 不等缓和曲线计算公式及坐标?
  13. 松下伺服电机uvw接线图_伺服电机接线图图解
  14. 论hr面试问题:离职原因
  15. VS (Visual Studio) 魔兽插件开发工具 AddOn Studio for WOW 1.0 含有LUA编辑
  16. 第四章:软件总体设计(4)此章结完
  17. ML01 -- KNN算法
  18. 闲聊HTML5的新特性
  19. 南瓜节(PumpkinFestival)| 终极南瓜系列挑战
  20. 逆---LanSet.exe

热门文章

  1. 淘宝开源Key/Value结构数据存储系统Tair技术剖析
  2. 【深度学习理论】一文搞透pytorch中的tensor、autograd、反向传播和计算图
  3. c++incline函数
  4. 08_提升方法Boosting1_统计学习方法
  5. 理解saltstack 里cmd.run 配合onlyif和unless使用
  6. 个人管理 - Learn More,Study Less!
  7. 初探 vue 插件开发
  8. Django模板自定义标签和过滤器,模板继承(extend),Django的模型层
  9. Docker、Kubernetes与PaaS不得不说的渊源
  10. javascript捕获事件event