一直以来对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提交浏览器