SpringSecurity 表单登录
SpringSecurity 表单登录
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/mylogin.html")
.loginProcessingUrl("/doLogin")
.defaultSuccessUrl("/index.html")
.failureHandler(new MyAuthenticationFailureHandler())
.usernameParameter("uname")
.passwordParameter("passwd")
.permitAll()
.and()
.logout()
.logoutRequestMatcher(new OrRequestMatcher(
new AntPathRequestMatcher("/logout1", "GET"),
new AntPathRequestMatcher("/logout2", "POST")))
.invalidateHttpSession(true)
.clearAuthentication(true)
.defaultLogoutSuccessHandlerFor((req,resp,auth)->{
resp.setContentType("application/json;charset=utf-8");
Map<String, Object> result = new HashMap<>();
result.put("status", 200);
result.put("msg", "使用 logout1 注销成功!");
ObjectMapper om = new ObjectMapper();
String s = om.writeValueAsString(result);
resp.getWriter().write(s);
},new AntPathRequestMatcher("/logout1","GET"))
.defaultLogoutSuccessHandlerFor((req,resp,auth)->{
resp.setContentType("application/json;charset=utf-8");
Map<String, Object> result = new HashMap<>();
result.put("status", 200);
result.put("msg", "使用 logout2 注销成功!");
ObjectMapper om = new ObjectMapper();
String s = om.writeValueAsString(result);
resp.getWriter().write(s);
},new AntPathRequestMatcher("/logout2","POST"))
.and()
.csrf().disable();
}
}
springSecurity需要自定义配置值 基本都是继承WebSecurityConfigurerAdapter
-
authorizeRequests表示开启权限配置,.anyRequest().authenticated()表示所有的请求都认证之后才能访问
-
and()方法返回HttpSecurity的实例
-
formLogin()表示开启表单登录配置
- loginPage 配置登录页面地址
- loginProcessingUrl 配置登录接口地址
- defaultSuccessUrl 登录成功后的跳转地址
- failureUrl表示登录失败后的跳转地址
- usernameParameter表示登录用户名的参数名
- passwordParameter 登录密码的参数名
- permitAll()表示和登录相关的页面和接口不做拦截 直接通过
其中loginProcessingUrl usernameParameter passwordParameter要和登录表单的配置一致。
.loginPage("/mylogin.html") // .loginProcessingUrl("/doLogin") .defaultSuccessUrl("/index.html") .failureHandler(new MyAuthenticationFailureHandler()) .usernameParameter("uname") .passwordParameter("passwd")
-
csrf().disable()表示禁用CSRF防御功能
登录成功
用户登录成功后除了defaultSuccessUrl方法可以实现登录成功的跳转之外,successForwardUrl也可以实现登录成功后的跳转,
defaultSuccessUrl 和successForwardUrl区别:
- defaultSuccessUrl表示当用户登录成功后,会自动重定向到登录之前的地址,如果用户本身就是访问的登录页面,登录成功后就会重定向到defaultSuccessUrl指定页面
- successForwardUrl不会考虑用户之前的访问地址,登录成功后通过服务器端跳转到successForwardUrl所指定的页面。
defaultSuccessUrl是客户端跳转重定向,successForwardUrl是通过服务端实现的跳转。
他们的接口都AuthenticationSuccessHandler
AuthenticationSuccessHandler有三个实现类
- SimpleUrlAuthenticationSuccessHandler 继承 AbstractAuthenticationTargetUrlRequestHandler 通过他的handle方法处理请求
- SavedRequestAwareAuthenticationSuccessHandler 在SimpleUrlAuthenticationSuccessHandler基础上增加了请求加缓存的功能,可以记录之前请求的地址,今儿在登录成功后重定向到开始访问的地址。
- ForwardAuthenticationSuccessHandler 是服务端的跳转
SavedRequestAwareAuthenticationSuccessHandler
defaultSuccessUrl 对应的是SavedRequestAwareAuthenticationSuccessHandler
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
SavedRequest savedRequest = this.requestCache.getRequest(request, response);
if (savedRequest == null) {
super.onAuthenticationSuccess(request, response, authentication);
} else {
String targetUrlParameter = this.getTargetUrlParameter();
if (!this.isAlwaysUseDefaultTargetUrl() && (targetUrlParameter == null || !StringUtils.hasText(request.getParameter(targetUrlParameter)))) {
this.clearAuthenticationAttributes(request);
String targetUrl = savedRequest.getRedirectUrl();
this.logger.debug("Redirecting to DefaultSavedRequest Url: " + targetUrl);
this.getRedirectStrategy().sendRedirect(request, response, targetUrl);
} else {
this.requestCache.removeRequest(request, response);
super.onAuthenticationSuccess(request, response, authentication);
}
}
}
- 首先从requestCache中获取缓存下来的请求 如果没有获取到缓存请求,就说明用户在访问登录页面之前并没有访问其他页面,此时直接调用父类的onAuthenticationSuccess方法来处理,重定向到defaultSuccessUrl指定的地址。
- 获取targetUrlParameter 拿到target参数后重定向地址。
- 如果targetUrlParameter不存在或者alwaysUseDefaultTargetUrl为true 缓存下来的请求没有意义,直接调用父类的onAuthenticationSuccess方法完成重定向 。targetUrlParameter存在 则重定向到targetUrlParameter中,alwaysUseDefaultTargetUrl为true 走默认
ForwardAuthenticationSuccessHandler
successForwardUrl对应ForwardAuthenticationSuccessHandler
public class ForwardAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private final String forwardUrl;
public ForwardAuthenticationSuccessHandler(String forwardUrl) {
Assert.isTrue(UrlUtils.isValidRedirectUrl(forwardUrl), () -> {
return "'" + forwardUrl + "' is not a valid forward URL";
});
this.forwardUrl = forwardUrl;
}
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
request.getRequestDispatcher(this.forwardUrl).forward(request, response);
}
}
主要调用getRequestDispatcher进行服务端请求转发
自定义AuthenticationSuccessHandler 实现类
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler{
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
Map<String, Object> resp = new HashMap<>();
resp.put("status", 200);
resp.put("msg", "登录成功!");
ObjectMapper om = new ObjectMapper();
String s = om.writeValueAsString(resp);
response.getWriter().write(s);
}
}
.successHandler(new MyAuthenticationSuccessHandler())
通过HttpServletResponse对象返回登录成功的json给前端
登录失败
failureUrl表示登录失败后的重定向到配置的页面,重定向是客户端的跳转,不方便携带请求失败的异常信息。
failureForwardUrl是服务端的跳转,可以携带登录异常信息。登录失败,自动跳转回登录页面,将错误信息展示出来。
他们的配置的是AuthenticationFailureHandler接口的实现类
SimpleUrlAuthenticationFailureHandler
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.security.web.authentication;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;
public class SimpleUrlAuthenticationFailureHandler implements AuthenticationFailureHandler {
protected final Log logger = LogFactory.getLog(this.getClass());
private String defaultFailureUrl;
private boolean forwardToDestination = false;
private boolean allowSessionCreation = true;
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
public SimpleUrlAuthenticationFailureHandler() {
}
public SimpleUrlAuthenticationFailureHandler(String defaultFailureUrl) {
this.setDefaultFailureUrl(defaultFailureUrl);
}
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
if (this.defaultFailureUrl == null) {
this.logger.debug("No failure URL set, sending 401 Unauthorized error");
response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
} else {
this.saveException(request, exception);
if (this.forwardToDestination) {
this.logger.debug("Forwarding to " + this.defaultFailureUrl);
request.getRequestDispatcher(this.defaultFailureUrl).forward(request, response);
} else {
this.logger.debug("Redirecting to " + this.defaultFailureUrl);
this.redirectStrategy.sendRedirect(request, response, this.defaultFailureUrl);
}
}
}
protected final void saveException(HttpServletRequest request, AuthenticationException exception) {
if (this.forwardToDestination) {
request.setAttribute("SPRING_SECURITY_LAST_EXCEPTION", exception);
} else {
HttpSession session = request.getSession(false);
if (session != null || this.allowSessionCreation) {
request.getSession().setAttribute("SPRING_SECURITY_LAST_EXCEPTION", exception);
}
}
}
}
当用户构造SimpleUrlAuthenticationFailureHandler对象时候传入defaultFailureUrl,也就是登录失败时要跳转的url。在onAuthenticationFailure方法中
-
如果defaultFailureUrl为null,直接通过response返回异常信息,否则调用saveException
-
saveException 如果forwardToDestination为true,表示通过服务器端跳转回到登录页面,此时就把异常信息放到request中。
-
回到onAuthenticationFailure方法,如果forwardToDestination为true,就通过服务器端跳回到登录页面,否则重定向到登录页面。
自定义AuthenticationFailureHandler实现类
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
response.setContentType("application/json;charset=utf-8");
Map<String, Object> resp = new HashMap<>();
resp.put("status", 500);
resp.put("msg", "登录失败!" + exception.getMessage());
ObjectMapper om = new ObjectMapper();
String s = om.writeValueAsString(resp);
response.getWriter().write(s);
}
}
通过HttpServletResponse对象返回登录失败的json给前端
注销登录
.logout()
.logoutUrl("")
.logoutRequestMatcher(new OrRequestMatcher(
new AntPathRequestMatcher("/logout1", "GET"),
new AntPathRequestMatcher("/logout2", "POST")))
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutSuccessUrl("")
- logout() 表示开启注销登录配置。
- logoutUrl 指定注销登录请求地址,默认GET请求,路径logout
- invalidateHttpSession 表示是否使session失效,默认为true
- clearAuthentication 表示是否清除认证信息,默认为true
- logoutSuccessUrl 表示注销登录后的跳转地址。
- logoutRequestMatcher 匹配多个注销登录
自定义注销成功的返回内容
.logout()
.logoutRequestMatcher(new OrRequestMatcher(
new AntPathRequestMatcher("/logout1", "GET"),
new AntPathRequestMatcher("/logout2", "POST")))
.invalidateHttpSession(true)
.clearAuthentication(true)
.defaultLogoutSuccessHandlerFor((req,resp,auth)->{
resp.setContentType("application/json;charset=utf-8");
Map<String, Object> result = new HashMap<>();
result.put("status", 200);
result.put("msg", "使用 logout1 注销成功!");
ObjectMapper om = new ObjectMapper();
String s = om.writeValueAsString(result);
resp.getWriter().write(s);
},new AntPathRequestMatcher("/logout1","GET"))
.defaultLogoutSuccessHandlerFor((req,resp,auth)->{
resp.setContentType("application/json;charset=utf-8");
Map<String, Object> result = new HashMap<>();
result.put("status", 200);
result.put("msg", "使用 logout2 注销成功!");
ObjectMapper om = new ObjectMapper();
String s = om.writeValueAsString(result);
resp.getWriter().write(s);
},new AntPathRequestMatcher("/logout2","POST"))
.and()
.csrf().disable();
defaultLogoutSuccessHandlerFor()两个参数 第一个是注销成功的回调,第二个是具体的注销请求。
- 点赞
- 收藏
- 关注作者
评论(0)