Shiro的authc过滤器的执行流程

1.先执行isAccessAllowed(),通过subject.isAuthenticated()判断当前session中的subject是否已经登陆过。如果在当前session即会话中已经登陆过,返回true,authc过滤器放行请求到loginUrl。
问题
这里会有一个问题,如果我登陆成功后,再次访问loginUrl,会执行isAccessAllowed()并返回true放行,那么我访问到了loginUrl,如果此时我在loginUrl中输入新的用户名密码,再提交则先执行isAccessAllowed(),因为当前session中的subject是已经登陆过的,isAccessAllowed()返回true,autch放行,请求又会到loginUrl。因为在登陆的情况下,再访问loginUrl则isAccessAllowed()始终返回true,不会执行到onAccessDenied()方法,即不会验证请求中的新的用户名和密码。
2.如果isAccessAllowed()是false即拒绝访问后执行onAccessDenied()方法:
2.1判断是否是登陆请请求(即request中的url和我们设置的loginUrl是否一致)
2.1.1如果请求的url和我们在配置文件中设置的loginUrl一样
2.1.1.1如果是get请求,则返回true,即该过滤器连放行,让请求访问到loginUrl
2.1.1.2如果是post请求,则创建subjet和tocken 调用subject的login方法进行认证(即开始执行realm的doGetAuthenticationInfo方法)
2.1.1.2.1如果认证成功则会返回false阻止filterChain继续执行即不让请求达到loginUrl,而是在这里直接重定向我们上次访问的非logurl的请求地址去(这个请求地址在你访问的时候已经被保存到session中了)如果没有上次访问的地址,则到我们设置的SuccessUrl
2.1.1…2.2如果认证失败则会返回true,将认证失败的异常信息放到reqeust属性中,即放行让fliterChain继续执行,让请求达到loginUrl。
2.2如果否即request中的url不是loginUrl,则保存请求(应该是到session里),再将请求重定向到loginUrl(浏览器又会访问通过get方法访问loginUrl,又会被authc拦截,再重複上面流程,此时是登陆请求且是GET请求则authc会放行访问到loginUrl),执行完重定向后返回false阻止filterChain继续执行。

综上所述:
只有以下四种情况会到loginUrl:
//1.还没有登陆成功的情况下:get请求我们在配置文件中设置的loginUrl,authc会放行请求到这里
//2.还没有登陆成功的情况下:post请求我们在配置文件中设置的loginUrl,authc在认证失败后会让浏览器重定向到这里
//3.还没有登陆成功的情况下:请求(不管post还是get)的页面不是loginUrl且需要authc过滤,那么authc也会让浏览器重定向到这里
//4.登陆成功后,浏览器再次访问loginUrl(不管post或get),authc也会放行到这里。
怎么解决上面登陆成功后再访问loginUrl,不会执行新用户认证的问题呢?只有重写authc过滤器的isAccessAllowed()方法

public class MyAuthcFilter extends FormAuthenticationFilter {
	@Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
    {
		System.out.println("执行自定义过滤");
		//如果请求的是loginUrl 并且是POST请求,那么肯定是要验证密码的,这里直接返回false 就会执行onAcessDenied()方法
        if (isLoginRequest(request, response) && isLoginSubmission(request, response))
        {
        	return false;
        }
        //如果是其他请求 则执行父类的方法
      return super.isAccessAllowed(request, response, mappedValue);
    }
}

最后再配置文件中注册该类,覆盖掉shiro原本的过滤器FormAuthenticationFilter:

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" />
		<property name="loginUrl" value="/login" />
		<property name="successUrl" value="/index.jsp" />
		<property name="unauthorizedUrl" value="/unauthorized.jsp" />
		<property name="filters">
			<map>
				<entry key="authc" value-ref="myAuthcFilter" />
			</map>
		</property>
		<property name="filterChainDefinitions">
			<value>
				# some example chain definitions:
				/login = authc
				/logout = logout
				/1.jsp = user
				/** = authc
				# more URL-to-FilterChain definitions here
			</value>
		</property>
	</bean>

login的写法:

@Controller
public class UsersController {
	@RequestMapping("login")
	public String login(HttpServletRequest req) {
		//只有
		//1.还没有登陆成功的情况下:get请求我们在配置文件中设置的loginUrl,authc会放行请求到这里
		//2.还没有登陆成功的情况下:post请求我们在配置文件中设置的loginUrl,authc在认证失败后会让浏览器重定向到这里
		//3.还没有登陆成功的情况下:请求(不管post还是get)的页面不是loginUrl且需要authc过滤,那么authc也会让浏览器重定向到这里
		//4.登陆成功后,浏览器再次访问loginUrl(不管post或get),authc也会放行到这里。如果我们在自定义的过滤器中
		//设置成如果是POST请求的loginUrl,我们返回false。那么post请求的loginUrl就会执行在过滤器中执行onAcessDenied()方法,如果post的loginUrl验证失败了会到这里,如果验证成功则到secessUrl这里。
		 String errorClassName = (String) req.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
	        if(UnknownAccountException.class.getName().equals(errorClassName)) {
	        	req.setAttribute("error", "用户名/密码错误");
	        } else if(IncorrectCredentialsException.class.getName().equals(errorClassName)) {
	        	req.setAttribute("error", "用户名/密码错误");
	        } else if(errorClassName != null) {
	        	req.setAttribute("error", "未知错误:" + errorClassName);
	        }
		return "login.jsp";
	}
}

session和cookie:
通过浏览器第一次发送http请求时,服务器会创建一个session和cookie(cookie中保存sessionid),这个session服务器的默认时间30分钟,可以设置。服务第一次响应时也把cookie放到响应中给浏览器,浏览器
收到cookie后,会判断cookie有没有设置过期时间,如果没有则只保存在内存中。如果有则存到硬盘里。
如果只是保存到内存中,服务器端的session依然会保留30分钟。那么浏览器一关闭,cookie消失,sessionid也消失了。。但此时打开浏览器再访问服务器时,虽然服务器的session依然存在,但浏览器中的cookie(sessionid)消失了
浏览器发送的请求头里没有cookie(没有sessionid),服务器会当作一个新的请求,会再创建一个新session。服务器中的之前的session 30分钟侯清除。
如果保存到硬盘里了, 服务器端的session依然会保留30分钟。那么关闭浏览器后,再打开浏览器访问服务器时,浏览器会找到存到硬盘里的cookie(sessionId), 浏览器再次请求服务器时会带上cookie,服务器收到请求后发现有cookie(sessionId)并且服务器
端的session也存在。那么服务器就依然会使用之前的session。不会再创建一个新的session。
所以session默认关闭浏览器就失效了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Apache Shiro是一个强大的安全框架,用于Java应用程序,提供了身份验证、授权和会话管理等功能。在Shiro中,注册过滤器是一个常见的步骤,用于在HTTP请求通过应用程序时应用安全检查。 **如何在Shiro中注册过滤器:** 1. **添加依赖**:首先,你需要在项目的pom.xml或build.gradle文件中添加Shiro的依赖。 2. **配置Web过滤器**:在Spring Boot项目中,通常会在WebMvcConfigurer接口的实现类中注册过滤器。例如: ```java @Configuration public class ShiroConfig implements WebMvcConfigurer { @Autowired private SecurityManager securityManager; @Override public void addViewControllers(ViewControllerRegistry registry) { // 其他配置... } @Override public void addFilter(ServletFilterRegistrationBean<?> filterRegistrationBean) { filterRegistrationBean.setFilter(securityManager.createFilterChainResolver().getFilter链名称()); filterRegistrationBean.addUrlPatterns("/*"); filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST); } } ``` 这里的`securityManager.createFilterChainResolver().getFilterChain()`会返回Shiro过滤器链,这个链包含了所有需要的应用过滤器,包括身份验证和授权过滤器。 3. **创建Filter链**:在Shiro的配置中,你需要定义过滤器链,通常使用`HttpSecurity`的`authorizeRequests()`方法来指定哪些URL需要特定的权限。 4. **身份验证过滤器**:Shiro提供了多种身份验证过滤器,如BasicAuthFilter、FormAuthenticationFilter等,你可以根据需求选择并配置。 5. **登录处理**:配置一个登录处理程序(LoginUrlAuthenticationFilter),定义用户登录失败后的重定向URL。 6. **退出处理**:记得配置一个退出过滤器,以便用户在注销时清除会话和权限信息。 **相关问题--:** 1. Shiro过滤器链是如何组织的? 2. 如何在Shiro中自定义身份验证过滤器? 3. Spring Boot集成Shiro后,如何配置登录和退出流程?

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值