SpringSecurity 表单登录
@Configurationpublic 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()两个参数 第一个是注销成功的回调,第二个是具体的注销请求。
总结
这篇文章主要讲了 Spring Security 登录成功和登录失败以及注销登录的逻辑,希望对你有帮助。
评论