shiro的FormAuthenticationFilter的做用

1、背景

    一直以來對shiro的formAuthenticationFilter的工做流程有疑惑,今天終於明白了。這篇文檔不是記錄formAuthenticationFilter的內部流程,或者說具體的內部代碼是怎麼工做的。而是記錄了將shiro集成到springboot中時,使用formAuthenticationFilter如何攔截、redirect請求。web

2、基礎配置

shiro的配置

@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

3、流程

一、用戶提交了一個form表單,提交的地址是/sys/login,參數包括username和password。
二、formAuthenticationFilter攔截到了該請求,執行AuthorizingRealm裏的登陸邏輯。
三、若是登陸成功,將會執行redirect到/sys/success。若是登陸失敗,將會執行redirect到/sys/login。apache

4、疑惑

一、用戶在沒有登陸的時候,任意提交一個表單,會不會執行登陸邏輯。
答案:不會。任意提交的表單,登陸地址若是不是/sys/login,首先也會被formAuthenticationFilter攔截到,可是攔截到之後由於校驗到沒有session,即用戶尚未登陸,會直接redirect到/sys/login。
二、登陸失敗後如何處理。
登陸失敗後,首先會執行formAuthenticationFilter中的onLoginFailure,這個函數是繼承下來的,原始的org.apache.shiro.web.filter.authc.FormAuthenticationFilter就有這個函數,個人子類FormAuthenticationFilter是繼承了該函數。登陸失敗後,能夠在該函數中根據exception來加入一些中文提示,放到request裏,再redirect到/sys/login之後,就能夠給出登陸錯誤的緣由提示。json

5、個人formAuthenticationFilter

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);  
  }  
}

6、瀏覽器提交數據的方式

一、form提交,能夠是post,也能夠是get
二、form-data,提交文件
三、json
四、xml
我一直覺得form表單提交必須是post提交瀏覽器

相關文章
相關標籤/搜索