版权声明:士,不可以不弘毅,任重而道远 https://blog.csdn.net/superbeyone/article/details/84668867
Spring Security个性化用户认证流程
1. 自定义登录页面
http.formLogin().loginPage("/tdt-siginIn.html")
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @Project: tdt-security
* @ClassName: BrowserSecurityConfig
* @Description: 浏览器配置类
* @Author: Mr.superbeyone
* @Create: 2018-11-28 16:44
**/
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder BCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() //想用默认的HttpBasic登录使用 http.httpBasic()
.loginPage("/tdt-signIn.html")//自定义登录页
.loginProcessingUrl("/authentication/form")//接收表单Url
.and()
.authorizeRequests()//下面的配置都是授权配置
.antMatchers("/tdt-signIn.html")
.permitAll()
.anyRequest()//任何请求
.authenticated()//都需要身份认证
.and()
.csrf().disable();//关闭跨站请求防护
}
}
- 自定义登录页面位置
- 自定义登录页面简单示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<h2>标准登录页面</h2>
<h3>表单登录</h3>
<form action="/authentication/form" method="post">
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="username" id="username"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password" id="password"></td>
</tr>
<tr>
<td colspan="2">
<button type="submit">提交</button>
</td>
</tr>
</table>
</form>
</body>
</html>
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Fri Nov 30 21:43:53 CST 2018
There was an unexpected error (type=Forbidden, status=403).
Could not verify the provided CSRF token because your session was not found.
该403错误是Spring Security
默认阻止跨站请求
- 登录成功后返回结果数据
自定义登录页设置
2. 自定义登录成功处理
AuthenticationSuccessHandler
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @Project: tdt-security
* @ClassName: TdtAuthenticationSuccessHandler
* @Author: Mr.superbeyone
* @Time: 2018-12-01 15:19
* @Description: 自定义登录成功处理
**/
@Component
public class TdtAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private ObjectMapper objectMapper;
/**
*
* @param request
* @param response
* @param authentication 封装认证信息(包括UserDetails)
* @throws IOException
* @throws ServletException
*/
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
logger.info("登录成功");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(objectMapper.writeValueAsString(authentication));
}
}
- 设置配置生效
import com.tdt.security.browser.authentication.TdtAuthenticationSuccessHandler;
import com.tdt.security.properties.SecurityProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @Project: tdt-security
* @ClassName: BrowserSecurityConfig
* @Description: 浏览器配置类
* @Author: Mr.superbeyone
* @Create: 2018-11-28 16:44
**/
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
SecurityProperties securityProperties;
@Autowired
TdtAuthenticationSuccessHandler tdtAuthenticationSuccessHandler;
@Bean
public PasswordEncoder BCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() //想用默认的HttpBasic登录使用 http.httpBasic()
.loginPage("/authentication/require")
.loginProcessingUrl("/authentication/form")
.successHandler(tdtAuthenticationSuccessHandler)
.and()
.authorizeRequests()//下面的配置都是授权配置
.antMatchers("/authentication/require",
securityProperties.getBrowser().getLoginPage())
.permitAll()
.anyRequest()//任何请求
.authenticated()//都需要身份认证
.and()
.csrf().disable();//关闭跨站请求防护
}
}
- 访问示例:
3. 自定义登录失败处理
AuthenticationFailureHandler
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @Project: tdt-security
* @ClassName: TdtAuthenticationFailureHandler
* @Author: Mr.superbeyone
* @Time: 2018-12-01 15:51
* @Description: 自定义登录失败处理
**/
@Component
public class TdtAuthenticationFailureHandler implements AuthenticationFailureHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private ObjectMapper objectMapper;
/**
* @param request
* @param response
* @param exception 登录异常
* @throws IOException
* @throws ServletException
*/
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
logger.info("登录失败");
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(objectMapper.writeValueAsString(exception));
}
}
- 设置配置生效
import com.tdt.security.browser.authentication.TdtAuthenticationFailureHandler;
import com.tdt.security.browser.authentication.TdtAuthenticationSuccessHandler;
import com.tdt.security.properties.SecurityProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @Project: tdt-security
* @ClassName: BrowserSecurityConfig
* @Description: 浏览器配置类
* @Author: Mr.superbeyone
* @Create: 2018-11-28 16:44
**/
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
SecurityProperties securityProperties;
@Autowired
TdtAuthenticationSuccessHandler tdtAuthenticationSuccessHandler;
@Autowired
TdtAuthenticationFailureHandler tdtAuthenticationFailureHandler;
@Bean
public PasswordEncoder BCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() //想用默认的HttpBasic登录使用 http.httpBasic()
.loginPage("/authentication/require")
.loginProcessingUrl("/authentication/form")
.successHandler(tdtAuthenticationSuccessHandler)
.failureHandler(tdtAuthenticationFailureHandler)
.and()
.authorizeRequests()//下面的配置都是授权配置
.antMatchers("/authentication/require",securityProperties.getBrowser().getLoginPage())
.permitAll()
.anyRequest()//任何请求
.authenticated()//都需要身份认证
.and()
.csrf().disable();//关闭跨站请求防护
}
}
4. 扩展,返回结果类型可配置
application.yml
tdt:
security:
browser:
loginPage: /demo-signIn.html
loginType: REDIRECT
LoginType
/**
* @Project: tdt-security
* @ClassName: LoginType
* @Author: Mr.superbeyone
* @Time: 2018-12-01 16:16
* @Description: 登录结果返回类型配置项
**/
public enum LoginType {
REDIRECT,
JSON
}
BrowserProperties
/**
* @Project: tdt-security
* @ClassName: BrowserProperties
* @Author: Mr.superbeyone
* @Time: 2018-11-30 23:07
* @Description: 自定义浏览器配置项
**/
public class BrowserProperties {
private String loginPage = "/tdt-signIn.html";
private LoginType loginType = LoginType.JSON;//默认返回JSON
public String getLoginPage() {
return loginPage;
}
public void setLoginPage(String loginPage) {
this.loginPage = loginPage;
}
public LoginType getLoginType() {
return loginType;
}
public void setLoginType(LoginType loginType) {
this.loginType = loginType;
}
}
SecurityProperties
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @Project: tdt-security
* @ClassName: SecurityProperties
* @Author: Mr.superbeyone
* @Time: 2018-11-30 23:05
* @Description: 自定义配置项
**/
@ConfigurationProperties("tdt.security")
public class SecurityProperties {
private BrowserProperties browser = new BrowserProperties();
public BrowserProperties getBrowser() {
return browser;
}
public void setBrowser(BrowserProperties browser) {
this.browser = browser;
}
}
SecurityCoreConfig
import com.tdt.security.properties.SecurityProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* @Project: tdt-security
* @ClassName: SecurityCoreConfig
* @Author: Mr.superbeyone
* @Time: 2018-11-30 23:13
* @Description: Security核心模块配置,让SecurityProperties配置类生效
**/
@Configuration
@EnableConfigurationProperties(SecurityProperties.class)
public class SecurityCoreConfig {
}
- 成功处理
SavedRequestAwareAuthenticationSuccessHandler
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tdt.security.properties.LoginType;
import com.tdt.security.properties.SecurityProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @Project: tdt-security
* @ClassName: TdtAuthenticationSuccessHandler
* @Author: Mr.superbeyone
* @Time: 2018-12-01 15:19
* @Description: 自定义登录成功处理
**/
@Component
public class TdtAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private ObjectMapper objectMapper;
@Autowired
private SecurityProperties securityProperties;
/**
* @param request
* @param response
* @param authentication 封装认证信息(包括UserDetails)
* @throws IOException
* @throws ServletException
*/
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
logger.info("登录成功");
if (LoginType.JSON.equals(securityProperties.getBrowser().getLoginType())) {
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(objectMapper.writeValueAsString(authentication));
} else {
super.onAuthenticationSuccess(request, response, authentication);//父类方法 (跳转)
}
}
}
- 失败处理
SimpleUrlAuthenticationFailureHandler
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tdt.security.properties.LoginType;
import com.tdt.security.properties.SecurityProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @Project: tdt-security
* @ClassName: TdtAuthenticationFailureHandler
* @Author: Mr.superbeyone
* @Time: 2018-12-01 15:51
* @Description: 自定义登录失败处理
**/
@Component
public class TdtAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private ObjectMapper objectMapper;
@Autowired
private SecurityProperties securityProperties;
/**
* @param request
* @param response
* @param exception 登录异常
* @throws IOException
* @throws ServletException
*/
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
logger.info("登录失败");
if (LoginType.JSON.equals(securityProperties.getBrowser().getLoginType())) {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(objectMapper.writeValueAsString(exception));
} else {
super.onAuthenticationFailure(request, response, exception);
}
}
}