1、用户信息从数据库获取

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

使用 jdbc-user-service 获取

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

   <security:authentication-manager>
<security:authentication-provider>
<security:jdbc-user-service data-source-ref="dataSource"/>
</security:authentication-provider>
</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 查询。

   <security:authentication-manager>
<security:authentication-provider>
<security:jdbc-user-service
data-source-ref="dataSource"
users-by-username-query="select username, password, enabled from t_user where username = ?" />
</security:authentication-provider>
</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 进行引用。

   <security:authentication-manager>
<security:authentication-provider user-service-ref="userDetailsService"/>
</security:authentication-manager> <bean id="userDetailsService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>

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

用户权限和用户组权限

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

   <security:authentication-manager>
<security:authentication-provider user-service-ref="userDetailsService"/>
</security:authentication-manager> <bean id="userDetailsService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource" ref="dataSource"/>
<property name="enableGroups" value="true"/>
</bean>

2、PasswordEncoder

使用内置的 PasswordEncoder

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

   <security:authentication-manager>
<security:authentication-provider user-service-ref="userDetailsService">
<security:password-encoder hash="md5"/>
</security:authentication-provider>
</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 的实现类都是支持的。

Spring Security 入门(1-4-2)Spring Security - 认证过程之AuthenticationProvider的扩展补充说明的更多相关文章

  1. Spring Security 入门(1-6-1)Spring Security - 配置文件解析和访问请求处理

    1.在pom.xml中添加maven坐标 <dependency> <groupId>org.springframework.security</groupId> ...

  2. Spring Security 入门(1-7)Spring Security - Session管理

    参考链接:https://xueliang.org/article/detail/20170302232815082 session 管理 Spring Security 通过 http 元素下的子元 ...

  3. Spring Security 入门(1-3-5)Spring Security - remember me!

    Remember-Me 功能 概述 Remember-Me 是指网站能够在 Session 之间记住登录用户的身份,具体来说就是我成功认证一次之后在一定的时间内我可以不用再输入用户名和密码进行登录了, ...

  4. Spring Security 入门(1-6-2)Spring Security - 内置的filter顺序、自定义filter、http元素和对应的filterChain

    Spring Security 的底层是通过一系列的 Filter 来管理的,每个 Filter 都有其自身的功能,而且各个 Filter 在功能上还有关联关系,所以它们的顺序也是非常重要的. 1.S ...

  5. Spring Security 入门(1-3-2)Spring Security - http元素 - intercept-url配置

    http元素下可以配置登录页面,也可以配置 url 拦截. 1.直接配置拦截url和对应的访问权限 <security:http use-expressions="false" ...

  6. Spring Security 入门(1-4-1)Spring Security - 认证过程

    理解时可结合一下这位老兄的文章:http://www.importnew.com/20612.html 1.Spring Security的认证过程 1.1.登录过程 - 如果用户直接访问登录页面 用 ...

  7. Spring Security 入门(1-3-1)Spring Security - http元素 - 默认登录和登录定制

    登录表单配置 - http 元素下的 form-login 元素是用来定义表单登录信息的.当我们什么属性都不指定的时候 Spring Security 会为我们生成一个默认的登录页面. 如果不想使用默 ...

  8. Spring Security 入门(1-2)Spring Security - 从 配置例子例子 开始我们的学习历程

    1.Spring Security 的配置文件 我们需要为 Spring Security 专门建立一个 Spring 的配置文件,该文件就专门用来作为 Spring Security 的配置. &l ...

  9. Spring Security入门(2-3)Spring Security 的运行原理 4 - 自定义登录方法和页面

    参考链接,多谢作者: http://blog.csdn.net/lee353086/article/details/52586916 http元素下的form-login元素是用来定义表单登录信息的. ...

随机推荐

  1. object转字符串

    1.obj.tostring() obj为空时,抛异常. 2.convert.tostring(obj) obj为空时,返回null: 3.(string)obj obj为空时,返回null:obj不 ...

  2. bootstrap 栅格系统 自动隐藏

    1 Container 顾名思义Container是栅格系统最外层的class,直接被container包裹的只能是row这个class.需要注意的是container自带左右各15px paddin ...

  3. 《Linux命令行与shell脚本编程大全》- 读书笔记2 - 更多的bash shell命令

    更多的bash shell命令 想检测进程,需要熟悉ps命令的用法.ps命令好比工具中的瑞士军刀,它能输出运行在系统上的所有程序的许多信息.默认情况下,ps命令只会显示运行在当前控制台下的属于当前用户 ...

  4. mysql授权报错

    mysql> grant all privileges on zabbix.* to zabbix@localhost identified by '<zabbix>';ERROR ...

  5. .NET Core快速入门教程 3、我的第一个.NET Core App (CentOS篇)

    一.前言 本篇开发环境?1.操作系统:CentOS7(因为ken比较偏爱CentOS7)2.SDK版本:.NET Core 2.0 Preview 你可能需要的前置知识1.了解如何通过Hyper-V安 ...

  6. ASP.NET没有魔法——ASP.NET MVC Razor与View渲染

    对于Web应用来说,它的界面是由浏览器根据HTML代码及其引用的相关资源进行渲染后展示给用户的结果,换句话说Web应用的界面呈现工作是由浏览器完成的,Web应用的原理是通过Http协议从服务器上获取到 ...

  7. JQuery操作option的添加、删除、取值

    1. $("#select_id").change(function(){//code...}); //为Select添加事件,当选择其中一项时触发 2. var checkTex ...

  8. alpha冲刺第八天

    一.合照 二.项目燃尽图 三.项目进展 首页文章显示部分 首页小功能福大地图完成 四.明日规划 发现爬取的数据是一整个网页的内容,而我们需要的仅仅是教务处通知的文章,在筛选方面还需要改进,查找如何进行 ...

  9. Alpha第三天

    Alpha第三天 听说 031502543 周龙荣(队长) 031502615 李家鹏 031502632 伍晨薇 031502637 张柽 031502639 郑秦 1.前言 任务分配是VV.ZQ. ...

  10. 第201621123043 《Java程序设计》第14周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结与数据库相关内容. 2. 使用数据库技术改造你的系统 2.1 简述如何使用数据库技术改造你的系统.要建立什么表?截图你的表设计. 2 ...