Spring Security(06)——AuthenticationProvider

简介: AuthenticationProvider 目录 1.1     用户信息从数据库获取 1.1.1    使用jdbc-user-service获取 1.1.2    直接使用JdbcDaoImpl 1.2     PasswordEncoder 1.2.1    使用内置的PasswordEncoder 1.2.2    使用自定义的PasswordEncoder          认证是由AuthenticationManager来管理的,但是真正进行认证的是AuthenticationManager中定义的AuthenticationProvider。

AuthenticationProvider

目录

1.1     用户信息从数据库获取

1.1.1    使用jdbc-user-service获取

1.1.2    直接使用JdbcDaoImpl

1.2     PasswordEncoder

1.2.1    使用内置的PasswordEncoder

1.2.2    使用自定义的PasswordEncoder

 

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

 

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

   <security:authentication-manager>

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

   </security:authentication-manager>

 

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

   <security:authentication-manager>

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

   </security:authentication-manager>

 

1.1     用户信息从数据库获取

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

 

1.1.1   使用jdbc-user-service获取

       Spring Security的命名空间中在authentication-provider下定义了一个jdbc-user-service元素,通过该元素我们可以定义一个从数据库获取UserDetailsUserDetailsServicejdbc-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=”ROLE_USER”,显然这是不匹配的,Spring Security不会给我们放行,通过指定jdbc-user-servicerole-prefix=”ROLE_”之后就会满足了。当role-prefix的值为“none”时表示没有前缀,当然默认也是没有的。

 

1.1.2   直接使用JdbcDaoImpl

       JdbcDaoImplUserDetailsService的一个实现。其用法和jdbc-user-service类似,只是我们需要把它定义为一个bean,然后通过authentication-provideruser-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的引用。如果就是上面这样配置的话我们数据库表结构也需要是标准的表结构。当然,如果我们的表结构和标准的不一样,可以通过usersByUsernameQueryauthoritiesByUsernameQuerygroupAuthoritiesByUsernameQuery属性来指定对应的查询SQL

用户权限和用户组权限

       JdbcDaoImpl使用enableAuthoritiesenableGroups两个属性来控制权限的启用。默认启用的是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>

 

1.2     PasswordEncoder

1.2.1   使用内置的PasswordEncoder

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

   <security:authentication-manager>

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

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

      </security:authentication-provider>

   </security:authentication-manager>

 

       其属性hash表示我们将用来进行加密的哈希算法,系统已经为我们实现的有plaintextshasha-256md4md5{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

<security:password-encoder hash="md5" base64="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

   <security:authentication-manager>

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

         <security:password-encoder hash="md5" base64="true">

            <security:salt-source system-wide="abc"/>

         </security:password-encoder>

      </security:authentication-provider>

   </security:authentication-manager>

 

       2)下面的配置将使用UserDetailsusername作为salt

   <security:authentication-manager>

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

         <security:password-encoder hash="md5" base64="true">

            <security:salt-source user-property="username"/>

         </security:password-encoder>

      </security:authentication-provider>

   </security:authentication-manager>

 

       3)下面的配置将使用自己实现的SaltSource获取salt。其中mySaltSource就是SaltSource实现类对应的bean的引用。

   <security:authentication-manager>

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

         <security:password-encoder hash="md5" base64="true">

            <security:salt-source ref="mySaltSource"/>

         </security:password-encoder>

      </security:authentication-provider>

   </security:authentication-manager>

 

       需要注意的是AuthenticationProvider进行认证时所使用的PasswordEncoder,包括它们的算法和规则都应当与我们保存用户密码时是一致的。也就是说如果AuthenticationProvider使用Md5PasswordEncoder进行认证,我们在保存用户密码时也需要使用Md5PasswordEncoder;如果AuthenticationProvider在认证时使用了username作为salt,那么我们在保存用户密码时也需要使用username作为salt。如:

   Md5PasswordEncoder encoder = new Md5PasswordEncoder();

   encoder.setEncodeHashAsBase64(true);

   System.out.println(encoder.encodePassword("user", "user"));

 

1.2.2   使用自定义的PasswordEncoder

       除了通过password-encoder使用Spring Security已经为我们实现了的PasswordEncoder之外,我们也可以实现自己的PasswordEncoder,然后通过password-encoderref属性关联到我们自己实现的PasswordEncoder对应的bean对象。

   <security:authentication-manager>

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

         <security:password-encoder ref="passwordEncoder"/>

      </security:authentication-provider>

   </security:authentication-manager>

  

   <bean id="passwordEncoder" class="com.xxx.MyPasswordEncoder"/>

 

       Spring Security内部定义有两种类型的PasswordEncoder,分别是org.springframework.security.authentication.encoding.PasswordEncoderorg.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 SecurityAPI文档。我们在通过password-encoder使用自定义的PasswordEncoder时两种PasswordEncoder的实现类都是支持的。

 

(注:本文是基于Spring Security3.1.6所写)

(注:原创文章,转载请注明出处。原文地址:http://elim.iteye.com/blog/2157769

 

 

 

目录
相关文章
|
安全 前端开发 Java
Spring Security笔记:自定义Login/Logout Filter、AuthenticationProvider、AuthenticationToken
在前面的学习中,配置文件中的...都是采用的auto-config="true"这种自动配置模式,根据Spring Security文档的说明: ------------------ auto-config Automatically registers a login form, BASIC authentication, logout services.
1589 0
|
4月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
888 0
|
5月前
|
人工智能 Java 测试技术
Spring Boot 集成 JUnit 单元测试
本文介绍了在Spring Boot中使用JUnit 5进行单元测试的常用方法与技巧,包括添加依赖、编写测试类、使用@SpringBootTest参数、自动装配测试模块(如JSON、MVC、WebFlux、JDBC等),以及@MockBean和@SpyBean的应用。内容实用,适合Java开发者参考学习。
629 0
|
1月前
|
JavaScript Java Maven
【SpringBoot(二)】带你认识Yaml配置文件类型、SpringMVC的资源访问路径 和 静态资源配置的原理!
SpringBoot专栏第二章,从本章开始正式进入SpringBoot的WEB阶段开发,本章先带你认识yaml配置文件和资源的路径配置原理,以方便在后面的文章中打下基础
277 3
|
1月前
|
Java 测试技术 数据库连接
【SpringBoot(四)】还不懂文件上传?JUnit使用?本文带你了解SpringBoot的文件上传、异常处理、组件注入等知识!并且带你领悟JUnit单元测试的使用!
Spring专栏第四章,本文带你上手 SpringBoot 的文件上传、异常处理、组件注入等功能 并且为你演示Junit5的基础上手体验
833 2
|
8月前
|
前端开发 Java 数据库
微服务——SpringBoot使用归纳——Spring Boot集成Thymeleaf模板引擎——Thymeleaf 介绍
本课介绍Spring Boot集成Thymeleaf模板引擎。Thymeleaf是一款现代服务器端Java模板引擎,支持Web和独立环境,可实现自然模板开发,便于团队协作。与传统JSP不同,Thymeleaf模板可以直接在浏览器中打开,方便前端人员查看静态原型。通过在HTML标签中添加扩展属性(如`th:text`),Thymeleaf能够在服务运行时动态替换内容,展示数据库中的数据,同时兼容静态页面展示,为开发带来灵活性和便利性。
396 0
|
8月前
|
XML Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于 xml 的整合
本教程介绍了基于XML的MyBatis整合方式。首先在`application.yml`中配置XML路径,如`classpath:mapper/*.xml`,然后创建`UserMapper.xml`文件定义SQL映射,包括`resultMap`和查询语句。通过设置`namespace`关联Mapper接口,实现如`getUserByName`的方法。Controller层调用Service完成测试,访问`/getUserByName/{name}`即可返回用户信息。为简化Mapper扫描,推荐在Spring Boot启动类用`@MapperScan`注解指定包路径避免逐个添加`@Mapper`
455 0
|
8月前
|
Java 测试技术 微服务
微服务——SpringBoot使用归纳——Spring Boot中的项目属性配置——少量配置信息的情形
本课主要讲解Spring Boot项目中的属性配置方法。在实际开发中,测试与生产环境的配置往往不同,因此不应将配置信息硬编码在代码中,而应使用配置文件管理,如`application.yml`。例如,在微服务架构下,可通过配置文件设置调用其他服务的地址(如订单服务端口8002),并利用`@Value`注解在代码中读取这些配置值。这种方式使项目更灵活,便于后续修改和维护。
152 0
|
8月前
|
SQL Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— application.yml 中对日志的配置
在 Spring Boot 项目中,`application.yml` 文件用于配置日志。通过 `logging.config` 指定日志配置文件(如 `logback.xml`),实现日志详细设置。`logging.level` 可定义包的日志输出级别,例如将 `com.itcodai.course03.dao` 包设为 `trace` 级别,便于开发时查看 SQL 操作。日志级别从高到低为 ERROR、WARN、INFO、DEBUG,生产环境建议调整为较高级别以减少日志量。本课程采用 yml 格式,因其层次清晰,但需注意格式要求。
805 0
|
4月前
|
缓存 JSON 前端开发
第07课:Spring Boot集成Thymeleaf模板引擎
第07课:Spring Boot集成Thymeleaf模板引擎
533 0
第07课:Spring Boot集成Thymeleaf模板引擎