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提交浏览器

相关文章
相关标签/搜索