# 使用 JUnit 测试 Spring Security Auth

> 原文： [https://howtodoinjava.com/junit/how-to-unit-test-spring-security-authentication-with-junit/](https://howtodoinjava.com/junit/how-to-unit-test-spring-security-authentication-with-junit/)

学习使用`InMemoryDaoImpl`使用 JUnit 测试用例测试 Spring Security认证。 还学习以编程方式构建完全填充的`authentication`对象，然后在应用程序中使用它。

## `SecurityContextHolder`

Spring Security 基于安全性上下文，本质上是静态的。 从本质上讲，这意味着您无需将其引用注入到 spring 容器中的 bean 或类中。 您只需使用[`SecurityContextHolder.getContext()`](http://static.springsource.org/spring-security/site/docs/3.0.x/apidocs/org/springframework/security/core/context/SecurityContextHolder.html#getContext%28%29)方法即可随时访问 spring 上下文。

该上下文具有实际主体或用户的引用，我们必须对其访问权限进行验证。

## Spring Security 单元测试 

我正在创建一个[简单的 Maven 项目](https://howtodoinjava.com/maven/create-a-simple-java-project-using-maven/)，并且将编写最少的代码，以便我可以专注于仅测试此帖子范围内的内容，即身份验证。 然后，我将用一个需要“ `ROLE_USER`”的单一方法编写一个演示服务类。 如果尝试访问此方法而没有“ `ROLE_USER`”，则将获得预期的`AccessDeniedException`。 很简单，不是吗？

#### 步骤 1）创建项目

让我们使用以下命令创建 Java 项目：

`Console`

```java
$ mvn archetype:generate -DgroupId=com.howtodoinjava 
							-DartifactId=SpringPasswordHashingDemo
							-DarchetypeArtifactId=maven-archetype-quickstart 
							-DinteractiveMode=false

```

现在，使用以下依赖项更新`pom.xml`，并运行命令`mvn:eclipse:eclipse`以支持项目 Eclipse。

`pom.xml`

```java
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.howtodoinjava</groupId>
  <artifactId>SpringPasswordHashingDemo</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>SpringPasswordHashingDemo</name>
  <url>http://maven.apache.org</url>
  <properties>
    <org.springframework.version>3.0.5.RELEASE</org.springframework.version>
  </properties>
  <dependencies>
  	 <!-- Spring Core -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.4</version>
      <scope>test</scope>
    </dependency>
    <dependency>
		<groupId>cglib</groupId>
		<artifactId>cglib</artifactId>
		<version>2.2</version>
	</dependency>
	<dependency>
	  <groupId>org.springframework</groupId>
	  <artifactId>spring-core</artifactId>
	  <version>${org.springframework.version}</version>
	</dependency>
	<dependency>
	  <groupId>org.springframework</groupId>
	  <artifactId>spring-expression</artifactId>
	  <version>${org.springframework.version}</version>
	</dependency>
	<dependency>
	  <groupId>org.springframework</groupId>
	  <artifactId>spring-beans</artifactId>
	  <version>${org.springframework.version}</version>
	</dependency>
	<dependency>
	  <groupId>org.springframework</groupId>
	  <artifactId>spring-context</artifactId>
	  <version>${org.springframework.version}</version>
	</dependency>
	<dependency>
	  <groupId>org.springframework</groupId>
	  <artifactId>spring-context-support</artifactId>
	  <version>${org.springframework.version}</version>
	</dependency>
	<dependency>
	  <groupId>org.springframework</groupId>
	  <artifactId>spring-test</artifactId>
	  <version>${org.springframework.version}</version>
	  <scope>test</scope>
	</dependency>

    <!-- Spring Security -->
	<dependency>
		<groupId>org.springframework.security</groupId>
		<artifactId>spring-security-core</artifactId>
		<version>${org.springframework.version}</version>
		<type>jar</type>
		<scope>compile</scope>
	</dependency>
	<dependency>
		<groupId>org.springframework.security</groupId>
		<artifactId>spring-security-web</artifactId>
		<version>${org.springframework.version}</version>
		<type>jar</type>
		<scope>compile</scope>
	</dependency>
	<dependency>
		<groupId>org.springframework.security</groupId>
		<artifactId>spring-security-config</artifactId>
		<version>${org.springframework.version}</version>
		<type>jar</type>
		<scope>compile</scope>
	</dependency>
	<dependency>
		<groupId>org.springframework.security</groupId>
		<artifactId>spring-security-taglibs</artifactId>
		<version>${org.springframework.version}</version>
		<type>jar</type>
		<scope>compile</scope>
	</dependency>

  </dependencies>
</project>

```

#### 步骤 2）创建安全配置文件

我创建了`application-security.xml`文件，并将安全配置放入其中。

`application-security.xml`

```java
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
	xmlns:beans="http://www.springframework.org/schema/beans" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	http://www.springframework.org/schema/security
	http://www.springframework.org/schema/security/spring-security-3.0.3.xsd">

	<global-method-security secured-annotations="enabled" />

	<authentication-manager alias="authenticationManager">
        <authentication-provider>
            <user-service>
                <user name="lokesh" password="password1" authorities="ROLE_USER" />
                <user name="admin" password="password2" authorities="ROLE_ADMIN" />
            </user-service>
        </authentication-provider>
    </authentication-manager>

    <beans:bean id="demoService" class="com.howtodoinjava.DemoService"/>

</beans:beans>

```

#### 步骤 3）建立受保护的方法

`DemoService.java`

```java
package com.howtodoinjava;

import org.springframework.security.access.annotation.Secured;

public class DemoService
{
	@Secured("ROLE_USER")
	public void method()
	{
		System.out.println("Method called");
	}
}

```

#### 步骤 4）使用 JUnit 测试身份验证

在 junit 测试中，我们将以编程方式配置 spring 上下文，然后将通过默认用户详细信息服务中的用户名访问用户。 在极端情况下，它是**内存中实现**，在您的情况下，它可能与某些[基于 jdbc 的用户详细信息服务](https://howtodoinjava.com/spring/spring-security/jdbc-user-service-based-spring-security-example/)或某些其他[自定义用户详细信息服务](https://howtodoinjava.com/spring/spring-security/custom-userdetailsservice-example-for-spring-3-security/)不同。 因此，请相应地修改查找。

我们将测试各种方案，例如有效用户，无效用户，无效角色等。您可以根据选择添加/删除方案。

`TestDemoService.java`

```java
package com.howtodoinjava;

import java.util.ArrayList;
import java.util.List;

import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.memory.InMemoryDaoImpl;

public class TestDemoService {

	static ApplicationContext applicationContext = null;
	static InMemoryDaoImpl userDetailsService = null;

	/**
	 * Initialize the application context to re-use in all test cases
	 * */
	@BeforeClass
	public static void setup()
	{
		//Create application context instance
		applicationContext = new ClassPathXmlApplicationContext("application-security.xml");
		//Get user details service configured in configuration 
		userDetailsService = applicationContext.getBean(InMemoryDaoImpl.class);
	}

	/**
	 * Test the valid user with valid role
	 * */
	@Test 
	public void testValidRole()
	{
		//Get the user by username from configured user details service
		UserDetails userDetails = userDetailsService.loadUserByUsername ("lokesh");
		Authentication authToken = new UsernamePasswordAuthenticationToken (userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities());
		SecurityContextHolder.getContext().setAuthentication(authToken);
		DemoService service = (DemoService) applicationContext.getBean("demoService");
		service.method();
	}

	/**
	 * Test the valid user with INVALID role
	 * */
	@Test (expected = AccessDeniedException.class)
	public void testInvalidRole()
	{
		UserDetails userDetails = userDetailsService.loadUserByUsername ("lokesh");
		List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
		authorities.add(new GrantedAuthorityImpl("ROLE_INVALID"));
		Authentication authToken = new UsernamePasswordAuthenticationToken (userDetails.getUsername(), userDetails.getPassword(), authorities);
		SecurityContextHolder.getContext().setAuthentication(authToken);
		DemoService service = (DemoService) applicationContext.getBean("demoService");
		service.method();
	}

	/**
	 * Test the INVALID user 
	 * */
	@Test (expected = AccessDeniedException.class)
	public void testInvalidUser()
	{
		UserDetails userDetails = userDetailsService.loadUserByUsername ("admin");
		List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
		authorities.add(new GrantedAuthorityImpl("ROLE_INVALID"));
		Authentication authToken = new UsernamePasswordAuthenticationToken (userDetails.getUsername(), userDetails.getPassword(), authorities);
		SecurityContextHolder.getContext().setAuthentication(authToken);
		DemoService service = (DemoService) applicationContext.getBean("demoService");
		service.method();
	}

}

```

如您所见，所有测试用例均按预期通过。

学习快乐！

[**源码下载**](https://docs.google.com/file/d/0B7yo2HclmjI4akNlUVdXNDJtdDA/edit?usp=sharing)