Shiro Web 的设计目标仍是解决单体 Web 服务的安全问题,如配置 authc.loginUrl
登录页面,用户被禁止访问则重定向到登录页面。
显然,authc 过滤器的默认行为显然并不适合提供 REST API 的 Web 服务。
Shiro 简单易扩展,可以对 Shiro Web 进行定制化,从而更好支持 REST API。
目标如下所示:
Shiro Web 使用了 Filter 对 HTTP 请求和响应进行过滤。 javax.servlet.Filter
接口定义如下:
public interface Filter { public void init(FilterConfig filterConfig) throws ServletException; public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException; public void destroy(); }
在 Shiro Web 中 Filter 的实现是 org.apache.shiro.web.servlet.ShiroFilter
类。在 Shiro Spring 中 Filter 的实现是 org.apache.shiro.spring.web.SpringShiroFilter
类。
如果定义了两个 Filter,关键步骤如下:
doFilter()
方法; doFilter()
方法,从而执行 Filter Chain 中第二个 Filter 的 doFilter()
方法; doFilter()
方法,从而执行 Servlet 的 service()
方法; doFilter()
方法返回; doFilter()
方法返回;
在 Shiro Web 中,路径规则:
/user/** = authc /** = anon
会转化为一个 FilterChain,而 authc 和 anon 就是 Shiro Web 默认提供的 Filter 实现。
默认 Filter 表格:
名称 | 实现类 | |
---|---|---|
anon | org.apache.shiro.web.filter.authc.AnonymousFilter | |
authc | org.apache.shiro.web.filter.authc.FormAuthenticationFilter | |
authcBasic | org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter | |
logout | org.apache.shiro.web.filter.authc.LogoutFilter | |
noSessionCreation | org.apache.shiro.web.filter.session.NoSessionCreationFilter | |
perms | org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter | |
port | org.apache.shiro.web.filter.authz.PortFilter | |
rest | org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter | |
roles | org.apache.shiro.web.filter.authz.RolesAuthorizationFilter | |
ssl | org.apache.shiro.web.filter.authz.SslFilter | |
user | org.apache.shiro.web.filter.authc.UserFilter |
以 Spring Boot 集成 org.apache.shiro:shiro-spring-boot-web-starter 为例,演示如何自定义 Filter。
public class RestApiFilter extends FormAuthenticationFilter { // ① @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { Subject subject = getSubject(request, response); if (subject.isAuthenticated()) { // ② HttpServletResponse httpResponse = WebUtils.toHttp(response); httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED); } else { // ③ HttpServletResponse httpResponse = WebUtils.toHttp(response); httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN); } return false; } }
① 修改 authc 在访问禁止的行为,选择继承 org.apache.shiro.web.filter.authc.FormAuthenticationFilter
并覆盖其 onAccessDenied()
方法;
② 如果没有认证,返回 HTTP 401 Unauthorized;
③ 如果没有鉴权,返回 HTTP 403 Forbidden。
添加自定义 Filter:
@Configuration public class ShiroWebFilterConfiguration extends AbstractShiroWebFilterConfiguration { @Bean @Override protected ShiroFilterFactoryBean shiroFilterFactoryBean() { ShiroFilterFactoryBean bean = super.shiroFilterFactoryBean(); bean.getFilters().put("api", new RestApiFilter()); return bean; } }
使用自定义 Filter:
/api/** = api