写点什么

SpringSecurity 默认页面生成

作者:周杰伦本人
  • 2022 年 5 月 01 日
  • 本文字数:4165 字

    阅读完需:约 14 分钟

SpringSecurity 默认页面生成

springSecurity 过滤器


  • DefaultLoginPageGeneratingFilter 生成默认的登录页面

  • DefaultLogoutPageGeneratingFilter 生成默认的注销页面

DefaultLoginPageGeneratingFilter

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {    HttpServletRequest request = (HttpServletRequest)req;    HttpServletResponse response = (HttpServletResponse)res;    boolean loginError = this.isErrorPage(request);    boolean logoutSuccess = this.isLogoutSuccess(request);    if (!this.isLoginUrlRequest(request) && !loginError && !logoutSuccess) {        chain.doFilter(request, response);    } else {        String loginPageHtml = this.generateLoginPageHtml(request, loginError, logoutSuccess);        response.setContentType("text/html;charset=UTF-8");        response.setContentLength(loginPageHtml.getBytes(StandardCharsets.UTF_8).length);        response.getWriter().write(loginPageHtml);    }}
private String generateLoginPageHtml(HttpServletRequest request, boolean loginError, boolean logoutSuccess) { String errorMsg = "Invalid credentials"; if (loginError) { HttpSession session = request.getSession(false); if (session != null) { AuthenticationException ex = (AuthenticationException)session.getAttribute("SPRING_SECURITY_LAST_EXCEPTION"); errorMsg = ex != null ? ex.getMessage() : "Invalid credentials"; } }
StringBuilder sb = new StringBuilder(); sb.append("<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n <meta name=\"description\" content=\"\">\n <meta name=\"author\" content=\"\">\n <title>Please sign in</title>\n <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n </head>\n <body>\n <div class=\"container\">\n"); String contextPath = request.getContextPath(); if (this.formLoginEnabled) { sb.append(" <form class=\"form-signin\" method=\"post\" action=\"" + contextPath + this.authenticationUrl + "\">\n <h2 class=\"form-signin-heading\">Please sign in</h2>\n" + createError(loginError, errorMsg) + createLogoutSuccess(logoutSuccess) + " <p>\n <label for=\"username\" class=\"sr-only\">Username</label>\n <input type=\"text\" id=\"username\" name=\"" + this.usernameParameter + "\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n </p>\n <p>\n <label for=\"password\" class=\"sr-only\">Password</label>\n <input type=\"password\" id=\"password\" name=\"" + this.passwordParameter + "\" class=\"form-control\" placeholder=\"Password\" required>\n </p>\n" + this.createRememberMe(this.rememberMeParameter) + this.renderHiddenInputs(request) + " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n </form>\n"); }
if (this.openIdEnabled) { sb.append(" <form name=\"oidf\" class=\"form-signin\" method=\"post\" action=\"" + contextPath + this.openIDauthenticationUrl + "\">\n <h2 class=\"form-signin-heading\">Login with OpenID Identity</h2>\n" + createError(loginError, errorMsg) + createLogoutSuccess(logoutSuccess) + " <p>\n <label for=\"username\" class=\"sr-only\">Identity</label>\n <input type=\"text\" id=\"username\" name=\"" + this.openIDusernameParameter + "\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n </p>\n" + this.createRememberMe(this.openIDrememberMeParameter) + this.renderHiddenInputs(request) + " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n </form>\n"); }
Iterator var7; Entry relyingPartyUrlToName; String url; String partyName; if (this.oauth2LoginEnabled) { sb.append("<h2 class=\"form-signin-heading\">Login with OAuth 2.0</h2>"); sb.append(createError(loginError, errorMsg)); sb.append(createLogoutSuccess(logoutSuccess)); sb.append("<table class=\"table table-striped\">\n"); var7 = this.oauth2AuthenticationUrlToClientName.entrySet().iterator();
while(var7.hasNext()) { relyingPartyUrlToName = (Entry)var7.next(); sb.append(" <tr><td>"); url = (String)relyingPartyUrlToName.getKey(); sb.append("<a href=\"").append(contextPath).append(url).append("\">"); partyName = HtmlUtils.htmlEscape((String)relyingPartyUrlToName.getValue()); sb.append(partyName); sb.append("</a>"); sb.append("</td></tr>\n"); }
sb.append("</table>\n"); }
if (this.saml2LoginEnabled) { sb.append("<h2 class=\"form-signin-heading\">Login with SAML 2.0</h2>"); sb.append(createError(loginError, errorMsg)); sb.append(createLogoutSuccess(logoutSuccess)); sb.append("<table class=\"table table-striped\">\n"); var7 = this.saml2AuthenticationUrlToProviderName.entrySet().iterator();
while(var7.hasNext()) { relyingPartyUrlToName = (Entry)var7.next(); sb.append(" <tr><td>"); url = (String)relyingPartyUrlToName.getKey(); sb.append("<a href=\"").append(contextPath).append(url).append("\">"); partyName = HtmlUtils.htmlEscape((String)relyingPartyUrlToName.getValue()); sb.append(partyName); sb.append("</a>"); sb.append("</td></tr>\n"); }
sb.append("</table>\n"); }
sb.append("</div>\n"); sb.append("</body></html>"); return sb.toString();}
复制代码


(1) 在 doFilter 方法中 首先判断当前请求是否为登录出错请求,注销成功请求或者登录请求。如果这三个请求中的任意一个,就会在 DefaultLoginPageGeneratingFilter 中生成登录页面并返回,否则请求继续往下走,执行下一个过滤器。


  1. 如果当前请求为登录出错请求,注销成功请求或者登录请求,使用 generateLoginPageHtml 生成登录页面,如果有异常信息一同返回给前端

  2. 登录页面生成后通过 HttpServletResponse 将登录页面写回到前端,然后调用 return 方法跳出过滤器链。

DefaultLogoutPageGeneratingFilter

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {    if (this.matcher.matches(request)) {        this.renderLogout(request, response);    } else {        filterChain.doFilter(request, response);    }
}
private void renderLogout(HttpServletRequest request, HttpServletResponse response) throws IOException { String page = "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n <meta name=\"description\" content=\"\">\n <meta name=\"author\" content=\"\">\n <title>Confirm Log Out?</title>\n <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n </head>\n <body>\n <div class=\"container\">\n <form class=\"form-signin\" method=\"post\" action=\"" + request.getContextPath() + "/logout\">\n <h2 class=\"form-signin-heading\">Are you sure you want to log out?</h2>\n" + this.renderHiddenInputs(request) + " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Log Out</button>\n </form>\n </div>\n </body>\n</html>"; response.setContentType("text/html;charset=UTF-8"); response.getWriter().write(page);}
复制代码


请求到来之后,先判断是否注销请求/logout,如果是/logout 请求,则渲染一个注销请求的页面,否则走下一个过滤器。

总结


这就是 SpringSecurity 默认页面生成的大体逻辑,主要涉及 DefaultLoginPageGeneratingFilter 和 DefaultLogoutPageGeneratingFilter 这两个过滤器,逻辑也比较简单

发布于: 24 分钟前阅读数: 6
用户头像

还未添加个人签名 2020.02.29 加入

还未添加个人简介

评论

发布
暂无评论
SpringSecurity默认页面生成_5月月更_周杰伦本人_InfoQ写作社区