spring boot SSL
证书生成(脚本 springSSL.bat )
@echo off
cd %~dp0
set cert=spring
set passwd=123456
set keytool="%JAVA_HOME%\bin\keytool.exe"
for /f tokens^=2^ delims^=^" %%i in ('wmic nicconfig get ipaddress ^|findstr /i "192.168.0.1"') do set ip=%%i
echo %ip%
%keytool% -genkeypair -alias %cert% -dname CN=主体的共同名称(网址或IP),OU=组织单位,O=组织,L=城市或区域,ST=省/市/自治区,C=国家/地区 -keystore ./spring.p12 -storetype pkcs12 -keypass %passwd% -storepass %passwd% -keyalg RSA -validity 90 -ext san:c=IP:127.0.0.1,IP:%ip%
application.yml
tomcat:
port: 8443
ssl:
enable: true
key-store: spring.p12
key-password: 123456
key-store-password: 123456
key-store-type: pkcs12
key-alias: spring
Application.java
import java. io. File ;
import java. io. IOException ;
import org. apache. catalina. connector. Connector ;
import org. apache. coyote. http11. Http11NioProtocol ;
import org. mybatis. spring. annotation. MapperScan ;
import org. springframework. beans. factory. annotation. Value ;
import org. springframework. boot. SpringApplication ;
import org. springframework. boot. autoconfigure. SpringBootApplication ;
import org. springframework. boot. web. embedded. tomcat. TomcatServletWebServerFactory ;
import org. springframework. boot. web. servlet. server. ServletWebServerFactory ;
import org. springframework. context. ConfigurableApplicationContext ;
import org. springframework. context. annotation. Bean ;
import org. springframework. core. io. ClassPathResource ;
@SpringBootApplication
@MapperScan ( "com.toshiba.translate.mapper" )
public class Application {
private static ConfigurableApplicationContext cac;
public static void main ( String [ ] args) {
cac = SpringApplication . run ( Application . class , args) ;
}
public static void exitApplication ( ) {
int exitCode = SpringApplication . exit ( cac, ( ) -> 0 ) ;
System . exit ( exitCode) ;
}
@Bean
public ServletWebServerFactory servletContainer (
@Value ( "${tomcat.port:#{null}}" ) Integer httpsPort,
@Value ( "${tomcat.ssl.key-store:#{null}}" ) String keyStore,
@Value ( "${tomcat.ssl.key-password:#{null}}" ) String keyPassword,
@Value ( "${tomcat.ssl.key-store-password:#{null}}" ) String keyStorePassword,
@Value ( "${tomcat.ssl.key-store-type:pkcs12}" ) String keyStoreType,
@Value ( "${tomcat.ssl.key-alias:#{null}}" ) String keyAlias) {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory ( ) ;
factory. addAdditionalTomcatConnectors (
createSslConnector ( httpsPort, keyStore, keyPassword, keyStorePassword, keyStoreType, keyAlias) ) ;
return factory;
}
private Connector createSslConnector ( Integer httpsPort, String keyStore, String keyPassword,
String keyStorePassword, String keyStoreType, String keyAlias) {
Connector connector = new Connector ( ) ;
Http11NioProtocol protocol = ( Http11NioProtocol ) connector. getProtocolHandler ( ) ;
File keystore = null ;
try {
keystore = new ClassPathResource ( keyStore) . getFile ( ) ;
connector. setScheme ( "https" ) ;
connector. setPort ( httpsPort) ;
connector. setSecure ( true ) ;
protocol. setSSLEnabled ( true ) ;
protocol. setKeystoreFile ( keystore. getAbsolutePath ( ) ) ;
protocol. setKeyPass ( keyPassword) ;
protocol. setKeystorePass ( keyStorePassword) ;
protocol. setKeystoreType ( keyStoreType) ;
protocol. setKeyAlias ( keyAlias) ;
return connector;
} catch ( IOException ex) {
throw new IllegalStateException (
"can't access keystore: [" + keystore + "]" , ex) ;
}
}
}
WebSecurityConfig.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import com.alibaba.fastjson.JSONObject;
import com.toshiba.translate.service.CustomUserDetailsService;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService userService;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers().frameOptions().disable();
http.cors();
http.csrf().disable();
http.rememberMe().rememberMeParameter("remember-me").userDetailsService(userService).tokenValiditySeconds(10000);
http.addFilterAt(customUPFilter(), UsernamePasswordAuthenticationFilter.class);
http.authorizeRequests(authorizeRequests ->
authorizeRequests
.antMatchers("/", "/index.html", "/static/**/**","/docs/**","/*.ico").permitAll()
.anyRequest().authenticated())
.formLogin().permitAll()
.and().logout().disable();
http.userDetailsService(userService);
http.exceptionHandling(exceptionHandling->{
exceptionHandling.accessDeniedHandler((request, response, authentication) -> {
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();out.write("{\"code:\":\"403\",\"message\":\"权限不足,请联系管理员。\"}");out.flush();out.close();
});
});
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET","POST","PUT","DELETE","OPTIONS"));
configuration.setAllowedOrigins(Arrays.asList("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@Bean
UsernamePasswordAuthenticationFilter customUPFilter() throws Exception {
UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter() {
@SuppressWarnings("finally")
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
if (!request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
if(request.getContentType().contains(MediaType.APPLICATION_JSON_VALUE)){
System.out.println("CustomUsernamePasswordAuthenticationFilter():json");
UsernamePasswordAuthenticationToken authRequest = null;
try (InputStream is = request.getInputStream()){
BufferedReader streamReader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
StringBuilder responseStrBuilder = new StringBuilder();
String inputStr;
while ((inputStr = streamReader.readLine()) != null) {
responseStrBuilder.append(inputStr);
}
JSONObject jsonObject = JSONObject.parseObject(responseStrBuilder.toString());
String username = jsonObject.getString(super.getUsernameParameter());
String password = jsonObject.getString(super.getPasswordParameter());
if (username == null) {username = "";}
if (password == null) {password = "";}
username = username.trim();
authRequest = new UsernamePasswordAuthenticationToken(
username, password);
}catch (IOException e) {
e.printStackTrace();
authRequest = new UsernamePasswordAuthenticationToken(
"", "");
}finally {
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
} else {
System.out.println("CustomUsernamePasswordAuthenticationFilter():not json");
return super.attemptAuthentication(request, response);
}
}
};
filter.setAuthenticationManager(authenticationManagerBean());
filter.setAuthenticationSuccessHandler((request, response, authentication) -> {
response.sendRedirect("/successinfo");
});
filter.setAuthenticationFailureHandler((request, response, authentication) -> {
response.sendRedirect("/failureinfo");
});
return filter;
}
参考链接 spring boot . https://zhuanlan.zhihu.com/p/88692437 .