Rest API: 基本认证和摘要认证

用spring security实现Rest API的基本认证(Basic)和摘要认证(Digest):

Basic 认证

1. server - spring security配置

package com.pechen.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 
    public final static String REALM="MY_REALM";
     
    @Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN")
        .and().withUser("test").password("test").roles("USER");
    }
     
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    	http.csrf().disable()
        	.authorizeRequests()
	        .anyRequest().authenticated()
	        .and().httpBasic().realmName(REALM).authenticationEntryPoint(getBasicAuthEntryPoint());
//	        .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);//We don't need sessions to be created.
    }
    
    @Bean
    public CustomBasicAuthenticationEntryPoint getBasicAuthEntryPoint(){
        return new CustomBasicAuthenticationEntryPoint();
    }
    
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        // altough this seems like useless code,
        // its required to prevend spring boot auto-configuration
        return super.authenticationManagerBean();
    }

}
package com.pechen.config;

import java.io.IOException;
import java.io.PrintWriter;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
 
public class CustomBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
 
	@Override
	public void commence(final HttpServletRequest request, final HttpServletResponse response,
			final AuthenticationException authException) throws IOException, ServletException {
		response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
		response.addHeader("WWW-Authenticate", "Basic realm=\"" + getRealmName() + "\"");

		PrintWriter writer = response.getWriter();
		writer.println("HTTP Status 401 : " + authException.getMessage());
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		setRealmName(WebSecurityConfig.REALM);
		super.afterPropertiesSet();
	}
}

2. server - rest api

package com.pechen.rest;

import java.util.Map;

import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

/**
 * Authentication service.
 */
@RestController
@RequestMapping(path = "/")
public class RestService {
    @RequestMapping(path = "/login", method = RequestMethod.GET)
    public String login(@RequestHeader Map headers){
    	return "Login success...";
    }
}

3. client - rest template(加上Authorization的头部即可)

package com.pechen.test;

import java.util.Base64;

import org.junit.Test;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

public class AuthServiceTest {
	private HttpHeaders getHeaders(){
		String plainCredentials="admin:admin";
		String base64Credentials = Base64.getEncoder().encodeToString(plainCredentials.getBytes());
		
		HttpHeaders headers = new HttpHeaders();
		headers.add("Authorization", "Basic " + base64Credentials);
		return headers;
	}

	@Test
	public void testLogin() {
		RestTemplate restTemplate = new RestTemplate();
		HttpEntity request = new HttpEntity(getHeaders());
		ResponseEntity response = restTemplate.exchange("http://localhost:8080/login", HttpMethod.GET,
				request, String.class);
		System.out.println(response.getBody());
	}
}

Digest 认证

1. server - spring security配置

package com.pechen.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.www.DigestAuthenticationFilter;
 
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 
    public final static String REALM="MY_REALM";
     
    @Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN")
        .and().withUser("test").password("test").roles("USER");
    }
     
    @Override
    protected void configure(HttpSecurity http) throws Exception {
		http.csrf().disable()
			.authorizeRequests()
			.anyRequest().authenticated()
			.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
			.and().exceptionHandling().authenticationEntryPoint(getDigestEntryPoint())
			.and().addFilter(getDigestAuthenticationFilter(getDigestEntryPoint()));
    	
    }
    
	@Bean
	public MyDigestAuthenticationEntryPoint getDigestEntryPoint() {
		MyDigestAuthenticationEntryPoint digestAuthenticationEntryPoint = new MyDigestAuthenticationEntryPoint();
		digestAuthenticationEntryPoint.setKey("mykey");
		digestAuthenticationEntryPoint.setNonceValiditySeconds(120);
		digestAuthenticationEntryPoint.setRealmName(REALM);
		return digestAuthenticationEntryPoint;
	}

	public DigestAuthenticationFilter getDigestAuthenticationFilter(
			MyDigestAuthenticationEntryPoint digestAuthenticationEntryPoint) throws Exception {
		DigestAuthenticationFilter digestAuthenticationFilter = new DigestAuthenticationFilter();
		digestAuthenticationFilter.setAuthenticationEntryPoint(digestAuthenticationEntryPoint);
		digestAuthenticationFilter.setUserDetailsService(userDetailsServiceBean());
		return digestAuthenticationFilter;
	}
 
	@Override
	@Bean
	public UserDetailsService userDetailsServiceBean() throws Exception {
		return super.userDetailsServiceBean();
	}
}
package com.pechen.config;

import org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint;

public class MyDigestAuthenticationEntryPoint extends DigestAuthenticationEntryPoint {
	
	@Override
	public void afterPropertiesSet() throws Exception{
		super.afterPropertiesSet();
		setRealmName(WebSecurityConfig.REALM);
	}
}
2. server - rest api 同上
3. client - 配置rest template使用Digest认证

package com.pechen.rest;

import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

public class RestTempleteConfig {

	public RestTemplate getRestTemplate() {
		CloseableHttpClient client = HttpClientBuilder.create().setDefaultCredentialsProvider(provider())
				.useSystemProperties().build();
		HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactoryDigestAuth(
				client);

		return new RestTemplate(requestFactory);
	}

	private CredentialsProvider provider() {
		CredentialsProvider provider = new BasicCredentialsProvider();
		UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("admin", "admin");
		provider.setCredentials(AuthScope.ANY, credentials);
		return provider;
	}
}
package com.pechen.rest;

import java.net.URI;
import org.apache.http.HttpHost;
import org.apache.http.client.AuthCache;
import org.apache.http.client.HttpClient;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.impl.auth.DigestScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;

public class HttpComponentsClientHttpRequestFactoryDigestAuth extends HttpComponentsClientHttpRequestFactory {
	 
    public HttpComponentsClientHttpRequestFactoryDigestAuth(HttpClient client) {
        super(client);
    }
 
    @Override
    protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {
        return createHttpContext(uri);
    }
 
    private HttpContext createHttpContext(URI uri) {
        // Create AuthCache instance
        AuthCache authCache = new BasicAuthCache();
        // Generate DIGEST scheme object, initialize it and add it to the local auth cache
        DigestScheme digestAuth = new DigestScheme();
        // If we already know the realm name
        digestAuth.overrideParamter("realm", "myrealm");
        HttpHost targetHost = new HttpHost(uri.getHost(), uri.getPort());
        authCache.put(targetHost, digestAuth);
 
        // Add AuthCache to the execution context
        BasicHttpContext localcontext = new BasicHttpContext();
        localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);
        return localcontext;
    }
}
4. 使用rest template发送请求
package com.pechen.test;

import org.junit.Test;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import jdk.nashorn.internal.ir.annotations.Ignore;

public class RestClient {
	
	@Test
	public void whenSecuredRestApiIsConsumed_then200OK() {
	    RestTemplate restTemplate = new RestTempleteConfig().getRestTemplate();
	    String uri = "http://localhost:8080/login";
	    ResponseEntity entity = restTemplate.exchange(uri, HttpMethod.GET, null, String.class);
	    System.out.println(entity.getStatusCode());
	    System.out.println(entity.getBody());
	}
}









你可能感兴趣的:(Web开发)