首先道歉 没经过充分的测试就发文了 后来在review的时候发现我在map中同一个key塞了俩对象
这样只有最后添加的有效 在看了shiro相关文档之后找到了有效的解决方法
文章末尾我会补上Shiro自带的拦截器相关内容
写一个Shiro的过滤器 继承org.apache.shiro.web.filter.authc.UserFilter
import com.zzyk.common.model.vo.Message; import com.alibaba.fastjson.JSON; import org.apache.shiro.subject.Subject; import org.apache.shiro.web.filter.authc.UserFilter; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class GenericFilter extends UserFilter { @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; resp.setCharacterEncoding("UTF-8"); resp.setHeader("ContentType", "text/html;charset=UTF-8"); String requestedWith = req.getHeader("X-Requested-With"); if ("XMLHttpRequest".equals(requestedWith)) { Message message = new Message(); message.setCode(403); message.setMessage("请登录后操作"); resp.getWriter().write(JSON.toJSONString(message)); } else { this.saveRequestAndRedirectToLogin(request, response); } return false; } }
Shiro的配置类里面的配置我就全部放出来了 就看一下与这次配置相关的
@Bean(name = "shiroFilter") public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean(); factoryBean.setSecurityManager(securityManager); // 设置登录界面URL factoryBean.setLoginUrl(loginUrl); // 设置未经认证页面的URL factoryBean.setUnauthorizedUrl(unauthorizedUrl); // 设置登录成功后跳转的URL factoryBean.setSuccessUrl(indexUrl); HashMap<String, Filter> filter = new HashMap<>(); filter.put("authc", new GenericFilter()); filter.put("logout", new LogoutFilter()); factoryBean.setFilters(filter); // 需要认证的加到authc里面 // 不需要认证的加到anon里面 HashMap<String, String> filterChain = new HashMap<>(); filterChain.put("/customize/**", "anon"); filterChain.put("/plugins/**", "anon"); filterChain.put("/layuiadmin/**", "anon"); filterChain.put("/favicon.ico", "anon"); filterChain.put("/sys/login", "anon"); filterChain.put("/sys/status", "anon"); filterChain.put("/sys/captcha", "anon"); filterChain.put("/device/notice", "anon"); filterChain.put("/druid/**", "anon"); filterChain.put("/sys/logout", "logout"); filterChain.put("/**", "authc"); factoryBean.setFilterChainDefinitionMap(filterChain); return factoryBean; }
另外不知道为啥我用jquery的ajax发出的请求都没有X-Requested-With请求头(郁闷...)
我就包装了一下jquery的ajax 手动把这个请求头加上 顺便处理了一下跨域问题
function getJson(url, params, method, success) { $.ajax({ url: host + url, data: params, method: method, async: true, dataType: "json", xhrFields: { withCredentials: true }, crossDomain: true, beforeSend: function (xhr) { xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest") }, success: function (data) { if (data['code'] == 403) { alert(data['message']); top.location.href = 'login.html' } else { if (success) { success(data); } } }, error: function () { alert('服务器错误,请联系管理员'); } }); }
这样ajax和网页请求都能正常处理了
注意一个过滤器名只能配一个过滤器 一个资源可以配多个过滤器名 方法为逗号分割 例如
// 定义过滤器
HashMap<String, Filter> filter = new HashMap<>(); filter.put("authc", new GenericFilter()); filter.put("default", new FormAuthenticationFilter()); filter.put("logout", new LogoutFilter()); factoryBean.setFilters(filter);
// 定义过滤链 HashMap<String, String> filterChain = new HashMap<>(); filterChain.put("/**", "authc,default"); factoryBean.setFilterChainDefinitionMap(filterChain);
DefaultFilterChainManager 会默认添加 org.apache.shiro.web.filter.mgt.DefaultFilter 中声明的拦截器
public enum DefaultFilter { anon(AnonymousFilter.class), authc(FormAuthenticationFilter.class), authcBasic(BasicHttpAuthenticationFilter.class), logout(LogoutFilter.class), noSessionCreation(NoSessionCreationFilter.class), perms(PermissionsAuthorizationFilter.class), port(PortFilter.class), rest(HttpMethodPermissionFilter.class), roles(RolesAuthorizationFilter.class), ssl(SslFilter.class), user(UserFilter.class); }
拦截器说明
默认拦截器名 | 拦截器类 | 说明 | 主要参数 |
身份验证相关 org.apache.shiro.web.filter.authc | |||
authc | FormAuthenticationFilter |
基于表单的拦截器 |
usernameParam: 用户名(username) passwordParam: 密码(password) rememberMeParam: 记住密码(remember) loginUrl: 登录页面("/login.jsp") successUrl: 登录成功后重定向的页面 failureKeyAttribute: 登录失败后 错误信息存储(shiroLoginFailure) |
authcBasic | BasicHttpAuthenticationFilter |
Basic HTTP身份验证拦截器 就是浏览器弹出登录窗口的那种 |
applicationName: 登录框显示的信息(application) |
logout | LogoutFilter | 退出登录拦截器 | redirectUrl: 退出登录重定向的页面("/") |
user | UserFilter |
用户拦截器 用于验证用户是否通过身份验证 |
|
anon | AnonymousFilter | 匿名拦截器 无需认证即可访问 | |
授权相关 org.apache.shiro.web.filter.authz | |||
roles | RolesAuthorizationFilter | 角色授权拦截器 |
loginUrl: 登录页面("/login.jsp") unauthorizedUrl: 未授权跳转的页面 |
perms | PermissionsAuthorizationFilter | 权限授权拦截器 | |
未完全实现 1.3.2版本不可用 |
HostFilter |
主机地址拦截器 我调用直接抛异常说暂未实现 |
authorizedIps: 已授权的ip地址 deniedIPS: 已拒绝的ip地址 |
port | PortFilter | 端口拦截器 |
port: 允许通过的端口 如果是非指定端口访问 则重定向到该端口 |
rest | HttpMethodPermissionFilter |
rest风格拦截器 根据请求方法构建权限字符串 |
GET=read POST=create PUT=update DELETE=delete HEAD=read TEACE=read OPTIONS=read MKCOL=create |
ssl | SslFilter | SSL拦截器 |
无参数 只允许https请求通过 如果是非http请求会重定向到443端口 |
其他 | |||
org.apache.shiro.web.filter.session | |||
noSessionCreation | NoSessionCreationFilter |
不创建会话(Session)拦截器 调用subject.getSession(false)没问题 调用subject.getSession(true)会抛异常 DisabledSessionException |
节选自《跟我学SHiro》并重新排版,修改了部分内容