一直以來對shiro的formAuthenticationFilter的工做流程有疑惑,今天終於明白了。這篇文檔不是記錄formAuthenticationFilter的內部流程,或者說具體的內部代碼是怎麼工做的。而是記錄了將shiro集成到springboot中時,使用formAuthenticationFilter如何攔截、redirect請求。web
@Bean(name\="shiroFilter") public ShiroFilterFactoryBean shiroFilter(SecurityManager manager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(manager); //攔截器. Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); // 配置不會被攔截的連接 順序判斷 filterChainDefinitionMap.put("/static/\*\*", "anon"); //配置退出 過濾器,其中的具體的退出代碼Shiro已經替咱們實現了 filterChainDefinitionMap.put("/sys/logout", "logout"); //若是新增url,在此處增長過濾(可是我不想每新增一個路徑就在這裏配置一次,因此新增了一個filter,CheckLoginStatusFilter) filterChainDefinitionMap.put("/user","authc"); // 若是不設置默認會自動尋找Web工程根目錄下的"/login"頁面 shiroFilterFactoryBean.setLoginUrl("/sys/login"); // 登陸成功後要跳轉的連接 shiroFilterFactoryBean.setSuccessUrl("/sys/success"); //未受權界面; shiroFilterFactoryBean.setUnauthorizedUrl("/sys/unauthorized"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; }
上面的代碼中,設置了loginUrl是/sys/login,設置了successUrl是/sys/successspring
一、用戶提交了一個form表單,提交的地址是/sys/login,參數包括username和password。
二、formAuthenticationFilter攔截到了該請求,執行AuthorizingRealm裏的登陸邏輯。
三、若是登陸成功,將會執行redirect到/sys/success。若是登陸失敗,將會執行redirect到/sys/login。apache
一、用戶在沒有登陸的時候,任意提交一個表單,會不會執行登陸邏輯。
答案:不會。任意提交的表單,登陸地址若是不是/sys/login,首先也會被formAuthenticationFilter攔截到,可是攔截到之後由於校驗到沒有session,即用戶尚未登陸,會直接redirect到/sys/login。
二、登陸失敗後如何處理。
登陸失敗後,首先會執行formAuthenticationFilter中的onLoginFailure,這個函數是繼承下來的,原始的org.apache.shiro.web.filter.authc.FormAuthenticationFilter就有這個函數,個人子類FormAuthenticationFilter是繼承了該函數。登陸失敗後,能夠在該函數中根據exception來加入一些中文提示,放到request裏,再redirect到/sys/login之後,就能夠給出登陸錯誤的緣由提示。json
public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter { public static final String DEFAULT\_MESSAGE\_PARAM \= "message"; private String messageParam \= DEFAULT\_MESSAGE\_PARAM; private static final Logger logger \= LoggerFactory.getLogger(FormAuthenticationFilter.class); @Override protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) { String username = getUsername(request); String password = getPassword(request); logger.info("------------------username: {}, password: {}", username, password); if (password == null) { password = ""; } boolean rememberMe = isRememberMe(request); String host = StringUtils.getRemoteAddr((HttpServletRequest) request); return new UsernamePasswordToken(username, password.toCharArray(), rememberMe, host); } public String getMessageParam() { return messageParam; } @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { HttpServletRequest req = (HttpServletRequest)request; return super.onAccessDenied(request, response); } /\*\* \* 登陸失敗調用事件 \*/ @Override protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) { String className = e.getClass().getName(); String message = ""; if (UnknownAccountException.class.getName().equals(className)) { message = "用戶名錯誤, 請輸入正確的用戶名!"; } else if (IncorrectCredentialsException.class.getName().equals(className)) { message = "密碼錯誤, 請輸入正確的密碼; 若是忘記密碼請聯繫管理員重置您的密碼!"; } else if (e.getMessage() != null && StringUtils.startsWith(e.getMessage(), "msg:")) { message = StringUtils.replace(e.getMessage(), "msg:", ""); } else { message = "系統出現點問題,請稍後再試!"; e.printStackTrace(); // 輸出到控制檯 } request.setAttribute(getFailureKeyAttribute(), className); request.setAttribute(getMessageParam(), message); return true; } @Override protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception { System.out.println("登錄成功"); return super.onLoginSuccess(token, subject, request, response); } }
一、form提交,能夠是post,也能夠是get
二、form-data,提交文件
三、json
四、xml
我一直覺得form表單提交必須是post提交瀏覽器