shiro学习22-shiro提供的filter-AccessControlFilter

本文深入探讨了Shiro Web Filter中的AccessControlFilter类,解释了其核心方法和属性,包括如何控制资源访问,如何重定向未登录用户到登录页面,以及如何判断请求是否为登录请求。

这个类的javadoc中说明了这个类才是限制应用中的资源能否被访问的filter,我们先看的onPreHandle方法:

publicboolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
    return isAccessAllowed(request, response, mappedValue) || onAccessDenied(request, response, mappedValue);
}

 

可以发现他是调用的isAccessAllowed方法和onAccessDenied方法,只要两者有一个可以就可以了,从名字中我们也可以理解,他的逻辑是这样:先调用isAccessAllowed,如果返回的是true,则直接放行执行后面的filterservlet,如果返回的是false,则继续执行后面的onAccessDenied方法,如果后面返回的是true则也可以有权限继续执行后面的filterservelt

只有两个函数都返回false才会阻止后面的filterservlet的执行。

 

isAccessAllowed方法在这个类中都是抽象的,依靠实现类实现。onAccessDenied方法不是抽象的,但是调用了另一个抽象的方法:

org.apache.shiro.web.filter.AccessControlFilter.onAccessDenied(ServletRequest, ServletResponse)

这个方法忽略了之前配置的param参数。

 

这个类中还有其他的属性,比如getLoginUrl,这个很容易猜测,是当没有登录的时候重定向到登录界面的,这个方法就是获得登录界面的位置,默认是/login.jsp,如果我们的登录界面不是这个的话就要重写这个方法。

 

还有一个特别好使的方法

saveRequestAndRedirectToLogin(ServletRequest, ServletResponse),源码如下:

protected void saveRequestAndRedirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
        saveRequest(request);
        redirectToLogin(request, response);
}

 

 

显示保存了当前的request,然后重定向。

源码如下:

protected void saveRequest(ServletRequest request) {
        WebUtils.saveRequest(request);//关于webutils在别的博客中。
}
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
        String loginUrl = getLoginUrl();//重定向的界面就是到登录页面。
        WebUtils.issueRedirect(request, response, loginUrl); //关于webutils在别的博客中。
}

 

我们如果在其他类中需要重定向的话就可以直接使用它的WebUtils.issueRedirect(request,response,loginUrl)方法了。

 

另外这个类还提供了判断当前的请求路径是不是登录页面的功能:

 

protectedboolean isLoginRequest(ServletRequest request, ServletResponse response) {
        return pathsMatch(getLoginUrl(), request);
}

这个方法也可能用到。

 

 

继续看他的实现类,注意,现在有两个抽象方法,一个是isAccessAllowed,一个是onAccessDenied,这两参数不一样。

 

继承类:

·AuthenticationFilter

·AuthorizationFilter

·UserFilter

 


<!--[endif]-->

<think>好的,我现在需要帮助用户将他们的应用从使用ShiroSession迁移到Shiro JWT Token,同时处理用户信息的保存问题。首先,我需要理解用户当前的情况。他们之前用的是shiro-spring-boot-web-starter1.11.0,并且通过SecurityUtils.getSubject().getSession().setAttribute来保存用户信息到Session中。现在要改成JWT,所以需要替换Session机制。首先,我得考虑如何用JWT替代Session。Shiro本身支持自定义的Realm和Token,所以可能需要创建一个JWT的Realm。用户之前用的是Session存储用户信息,现在应该用JWT来携带用户信息,并且在请求中验证JWT的有效性。 接下来,需要处理用户认证流程的改变。原本的Session管理会自动处理用户的登录状态,现在改用JWT后,每次请求都需要携带Token。这意味着需要自定义一个Filter来处理HTTP请求中的JWTToken,比如从Header中提取Token,然后交给Shiro进行验证。然后是用户信息的保存问题。之前是存在Session中,现在可能需要将用户信息存储在JWT的Claims里,或者每次请求时从数据库或其他存储中加载。不过为了减少数据库查询,可能倾向于将必要信息直接放在JWT中,这样解析Token后可以直接获取用户信息,而不需要每次查询数据库。 另外,需要考虑Token的生成和刷新机制。用户登录成功后,生成JWTToken并返回给客户端。客户端后续的请求需要在Authorization头中携带这个Token。Shiro需要配置为无状态模式,因为不再依赖Session。可能还需要修改Shiro的配置,比如设置SecurityManager的SessionManager为禁用Session,或者使用默认的但关闭Session创建。同时,自定义的Realm需要实现doGetAuthenticationInfo方法,根据JWT Token进行认证。 用户提到的SecurityUtils.getSubject().getSession().setAttribute(ATTR_USER, sessionUser);这行代码现在需要调整,因为使用JWT后,Subject可能不会有Session了。所以需要找到替代方案,比如将用户信息存储在Token的Claims中,或者在每次认证时从Token中解析出用户信息。可能的问题点包括如何将JWT集成到Shiro的认证流程中,如何处理Token的过期和刷新,以及如何确保无状态环境下的安全性。需要确保自定义的Filter能够正确解析和验证Token,并且正确处理认证和授权异常。最后,可能需要编写示例代码来展示如何创建JWTRealm,配置Shiro,以及修改原有的用户信息存储方式。同时需要测试整个流程,确保用户登录、Token生成、请求验证以及用户信息获取都能正常工作。</think>从 Shiro Session 迁移到 JWT Token 的改造需要以下核心步骤: 1. **JWT 认证流程实现** ```java public class JwtFilter extends AccessControlFilter { @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { return false; // 始终走 onAccessDenied } @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { String jwt = getRequestToken((HttpServletRequest) request); if (!StringUtils.hasText(jwt)) { throw new AuthenticationException("Missing token"); } JwtToken token = new JwtToken(jwt); getSubject(request, response).login(token); return true; } private String getRequestToken(HttpServletRequest request) { return request.getHeader("Authorization"); } } ``` 2. **自定义 Realm** ```java public class JwtRealm extends AuthorizingRealm { public JwtRealm() { setCredentialsMatcher(new JwtCredentialsMatcher()); } @Override public boolean supports(AuthenticationToken token) { return token instanceof JwtToken; } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // 授权逻辑 } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String jwt = (String) token.getCredentials(); try { // 解析JWT获取用户信息 Claims claims = JwtUtil.parseToken(jwt); String username = claims.getSubject(); // 验证用户有效性(根据业务需求) User user = userService.loadUserByUsername(username); return new SimpleAuthenticationInfo(user, jwt, getName()); } catch (Exception e) { throw new AuthenticationException("Invalid token"); } } } ``` 3. **替换 Session 存储方案** 原来的 Session 存储代码: ```java SecurityUtils.getSubject().getSession().setAttribute(ATTR_USER, sessionUser); ``` 应改为将用户信息直接存入 JWT: ```java String jwt = JwtUtil.generateToken(user.getId(), user.getRoles()); response.setHeader("Authorization", jwt); ``` **改造原因:** 1. 无状态架构需求:Session 机制依赖服务端存储,与 JWT 的无状态特性冲突 2. 分布式系统扩展性:Session 需要共享存储方案,JWT 自带可验证凭据 3. 安全考虑:JWT 可包含数字签名防止篡改,且可设置有效期自动过期 4. 跨域支持:JWT 更易于实现跨域认证和微服务间的身份传递 **注意事项:** - 需要配置 Shiro 禁用 Session ```java @Bean public DefaultSecurityManager securityManager() { DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); manager.setRealm(jwtRealm()); manager.setSessionManager(sessionManager()); return manager; } private SessionManager sessionManager() { DefaultSessionManager sessionManager = new DefaultSessionManager(); sessionManager.setSessionValidationSchedulerEnabled(false); sessionManager.setSessionDAO(new MemorySessionDAO()); return sessionManager; } ``` - 需要处理 Token 刷新机制 - 需要实现黑名单机制处理主动注销
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值