原文: https://howtodoinjava.com/spring-security/spring-3-security-siteminder-pre-authentication-example/

到目前为止,我们已经了解了使用登录表单安全性自定义用户详细信息安全性以及更多此类与安全性相关的概念。 在这篇文章中,我举了一个场景示例,其中已经通过任何第三方应用程序或工具对使用进行了身份验证,例如站点监视程序,这是组中多个应用程序之间非常常见的接口。

在这种情况下,用户已在任何其他应用程序中进行了预身份验证,并使用网站提示器进入您的 Web 应用程序。 网站管理员会发送有关预认证用户的请求标头,您可以利用该标头进一步授权应用程序内的用户。 您不需要进一步验证用户,只需从数据库验证用户角色并在应用程序内部提供适当的访问权限即可。

请记住,网站管理员仅是示例,实际上,您可以使用任何第三方
应用程序来获得预先认证的用户。 在每种情况下,仅请求标头都会更改。

让我们逐步学习本教程。

步骤 1)Maven 依赖

我使用 maven 作为运行时依赖项,因此提供pom.xml。 如果使用的是 ANT,则下载相应的 JAR,并将其添加到类路径中。

pom.xml

  1. <properties>
  2. <spring.version>3.0.5.RELEASE</spring.version>
  3. <jackson-mapper-asl.version>1.9.9</jackson-mapper-asl.version>
  4. <jaxb-api.version>2.2.7</jaxb-api.version>
  5. </properties>
  6. <dependencies>
  7. <!-- Spring 3 dependencies -->
  8. <dependency>
  9. <groupId>org.springframework</groupId>
  10. <artifactId>spring-core</artifactId>
  11. <version>${spring.version}</version>
  12. <scope>runtime</scope>
  13. </dependency>
  14. <dependency>
  15. <groupId>org.springframework</groupId>
  16. <artifactId>spring-web</artifactId>
  17. <version>${spring.version}</version>
  18. <scope>runtime</scope>
  19. </dependency>
  20. <dependency>
  21. <groupId>org.springframework</groupId>
  22. <artifactId>spring-webmvc</artifactId>
  23. <version>${spring.version}</version>
  24. <scope>runtime</scope>
  25. </dependency>
  26. <!-- Spring Security -->
  27. <dependency>
  28. <groupId>org.springframework.security</groupId>
  29. <artifactId>spring-security-core</artifactId>
  30. <version>${spring.version}</version>
  31. <type>jar</type>
  32. <scope>runtime</scope>
  33. </dependency>
  34. <dependency>
  35. <groupId>org.springframework.security</groupId>
  36. <artifactId>spring-security-web</artifactId>
  37. <version>${spring.version}</version>
  38. <type>jar</type>
  39. <scope>runtime</scope>
  40. </dependency>
  41. <dependency>
  42. <groupId>org.springframework.security</groupId>
  43. <artifactId>spring-security-config</artifactId>
  44. <version>${spring.version}</version>
  45. <type>jar</type>
  46. <scope>runtime</scope>
  47. </dependency>
  48. <dependency>
  49. <groupId>org.springframework.security</groupId>
  50. <artifactId>spring-security-taglibs</artifactId>
  51. <version>${spring.version}</version>
  52. <type>jar</type>
  53. <scope>runtime</scope>
  54. </dependency>
  55. </dependencies>

步骤 2)更新web.xml文件

web.xml文件中没有太多内容。 只需添加上下文配置位置Spring Security 相关的过滤器映射即可。

web.xml

  1. <web-app>
  2. <display-name>www.howtodoinjava.com</display-name>
  3. <servlet>
  4. <servlet-name>spring-mvc</servlet-name>
  5. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  6. <load-on-startup>1</load-on-startup>
  7. </servlet>
  8. <servlet-mapping>
  9. <servlet-name>spring-mvc</servlet-name>
  10. <url-pattern>/*</url-pattern>
  11. </servlet-mapping>
  12. <context-param>
  13. <param-name>contextConfigLocation</param-name>
  14. <param-value>/WEB-INF/spring-mvc-servlet.xml</param-value>
  15. </context-param>
  16. <filter>
  17. <filter-name>springSecurityFilterChain</filter-name>
  18. <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  19. </filter>
  20. <filter-mapping>
  21. <filter-name>springSecurityFilterChain</filter-name>
  22. <url-pattern>/*</url-pattern>
  23. </filter-mapping>
  24. <listener>
  25. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  26. </listener>
  27. </web-app>

步骤 3)Spring Security 配置

这是最重要的步骤,因为在这里我们将配置与验证前安全性相关的映射。 让我们看一下文件:

spring-mvc-servlet.xml

  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:security="http://www.springframework.org/schema/security"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
  4. xmlns:mvc="http://www.springframework.org/schema/mvc"
  5. xmlns:aop="http://www.springframework.org/schema/aop"
  6. xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
  7. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  8. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
  9. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
  10. http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.3.xsd">
  11. <!-- Annotation are configuring the application -->
  12. <mvc:annotation-driven/>
  13. <!-- Scan this package for all config annotations -->
  14. <context:component-scan base-package="com.howtodoinjava.web" />
  15. <security:http use-expressions="true" auto-config="false" entry-point-ref="http403EntryPoint">
  16. <!-- Additional http configuration omitted -->
  17. <security:intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
  18. <security:custom-filter position="PRE_AUTH_FILTER" ref="siteminderFilter" />
  19. </security:http>
  20. <bean id="siteminderFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
  21. <property name="principalRequestHeader" value="SM_USER"/>
  22. <property name="authenticationManager" ref="authenticationManager" />
  23. </bean>
  24. <bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
  25. <property name="preAuthenticatedUserDetailsService">
  26. <bean id="userDetailsServiceWrapper" class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
  27. <property name="userDetailsService" ref="customUserDetailsService"/>
  28. </bean>
  29. </property>
  30. </bean>
  31. <security:authentication-manager alias="authenticationManager">
  32. <security:authentication-provider ref="preauthAuthProvider" />
  33. </security:authentication-manager>
  34. <bean id="customUserDetailsService" class="com.howtodoinjava.security.CustomUserDetailsService"></bean>
  35. <bean id="http403EntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"></bean>
  36. </beans>

让我们了解以下配置:

  1. mvc:annotation-driven用于告诉 spring 它需要在context:component-scan中指定的基本包中扫描注解,以搜索资源映射。
  2. security:http配置指定与安全性相关的配置和选项。 use-expressions告诉您,与security: intercept-url中的access属性匹配时,允许使用表达式,并应对其进行解析。
  3. security:custom-filter指定了自定义过滤器的定义,该过滤器将被调用以验证用户的有效性。
  4. PRE_AUTH_FILTER确保在其他身份验证/授权处理之前将调用此过滤器。 我为此定义了一个siteminder过滤器。 您可以将其命名为其他名称。
  5. principalRequestHeader很重要,因为一旦用户从另一个应用程序进入应用程序,它将检查请求标头属性。 因此,请第三方供应器提供的此标头在此处集成。
  6. authenticationManager最终使用了我在com.howtodoinjava.security.CustomUserDetailsService类中编写的customUserDetailsService。此类实现UserDetailsService接口,并具有一种方法loadUserByUsername()。 此方法必须返回类型为org.springframework.security.core.userdetails.UserDetails的经过身份验证的用户界面。 该对象将具有其他授权详细信息,例如用户角色,将用于进一步的安全性。

步骤 4)编写自定义UserDetailsService

此类将获取从第三方应用程序传递的用户名,并将用户名作为请求标头传递,例如在我们的情况下为SM_USER

CustomUserDetailsService.java

  1. package com.howtodoinjava.security;
  2. import org.springframework.dao.DataAccessException;
  3. import org.springframework.security.core.GrantedAuthority;
  4. import org.springframework.security.core.authority.GrantedAuthorityImpl;
  5. import org.springframework.security.core.userdetails.User;
  6. import org.springframework.security.core.userdetails.UserDetails;
  7. import org.springframework.security.core.userdetails.UserDetailsService;
  8. import org.springframework.security.core.userdetails.UsernameNotFoundException;
  9. public class CustomUserDetailsService implements UserDetailsService
  10. {
  11. public UserDetails loadUserByUsername(String username)
  12. throws UsernameNotFoundException, DataAccessException
  13. {
  14. System.out.println("username recieved :: " + username);
  15. @SuppressWarnings("deprecation")
  16. //Get this user details from database and set its roles also here
  17. UserDetails user = new User(username, "password", true, true, true, true,
  18. new GrantedAuthority[]{ new GrantedAuthorityImpl("ROLE_USER") });
  19. return user;
  20. }
  21. }

步骤 5)编写安全资源以进行验证

为了简单起见,我编写了两个非常基本的类。 我将尝试在没有请求标头“ SM_USER”的情况下访问它们。

DemoController.java

DemoController.java

  1. package com.howtodoinjava.web;
  2. @Controller
  3. @RequestMapping("/users")
  4. public class DemoController
  5. {
  6. @RequestMapping(method = RequestMethod.GET, value="/{id}", headers="Accept=application/xml")
  7. public @ResponseBody User getUserById(@PathVariable String id)
  8. {
  9. User user = new User();
  10. user.setFirstName("john");
  11. user.setLastName("adward");
  12. return user;
  13. }
  14. @RequestMapping(method = RequestMethod.GET, headers="Accept=application/xml")
  15. public @ResponseBody Users getAllUsers()
  16. {
  17. User user1 = new User();
  18. user1.setFirstName("john");
  19. user1.setLastName("adward");
  20. User user2 = new User();
  21. user2.setFirstName("tom");
  22. user2.setLastName("hanks");
  23. Users users = new Users();
  24. users.setUsers(new ArrayList<User>());
  25. users.getUsers().add(user1);
  26. users.getUsers().add(user2);
  27. return users;
  28. }
  29. }

Users.java

Users.java

  1. @XmlRootElement(name="users")
  2. @XmlAccessorType(XmlAccessType.NONE)
  3. public class Users
  4. {
  5. @XmlElement(name="user")
  6. private Collection<User> users;
  7. public Collection<User> getUsers() {
  8. return users;
  9. }
  10. public void setUsers(Collection<User> users) {
  11. this.users = users;
  12. }
  13. }

User.java

User.java

  1. @XmlRootElement(name="user")
  2. @XmlAccessorType(XmlAccessType.NONE)
  3. public class User {
  4. @XmlElement(name="first-name")
  5. private String firstName;
  6. @XmlElement(name="last-name")
  7. private String lastName;
  8. public String getFirstName() {
  9. return firstName;
  10. }
  11. public void setFirstName(String firstName) {
  12. this.firstName = firstName;
  13. }
  14. public String getLastName() {
  15. return lastName;
  16. }
  17. public void setLastName(String lastName) {
  18. this.lastName = lastName;
  19. }
  20. }

步骤 6)示范

让我们将应用程序部署在 tomcat 服务器中并进行测试。

情况 1:不带SM_USER请求头

这将引发以下异常:

  1. org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException: SM_USER header not found in request.
  2. at org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter.getPreAuthenticatedPrincipal(RequestHeaderAuthenticationFilter.java:43)
  3. at org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter.doAuthenticate(AbstractPreAuthenticatedProcessingFilter.java:98)
  4. at org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter.doFilter(AbstractPreAuthenticatedProcessingFilter.java:86)
  5. at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
  6. at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
  7. at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
  8. at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:79)
  9. at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
  10. at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:169)
  11. at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)

Spring Security Siteminder 预身份验证示例 - 图1

Spring security 预认证错误

情况 2:带SM_USER请求标头

这次,用户将可以访问资源。

Spring Security Siteminder 预身份验证示例 - 图2

Spring security 预认证成功

要下载以上教程的源代码,请点击以下下载链接。

下载源码

学习愉快!