在前后端分离的应用中,需要shiro授权失败时,返回json格式数据, 如下是在springboot应用中,前端ajax请求, shiro授权失败,返回json数据的应用实例
1, 在ShiroFilterFactoryBean类中增加如下两行代码:
2, 当然同时需要定义两个角色和权限返回json类
2.1 CustomRolesAuthorizationFilter 类
import com.alibaba.fastjson.JSONObject; import com.zhuangzi.springboot1101.configurations.JsonResult; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.StringUtils; import org.apache.shiro.web.filter.authz.AuthorizationFilter; import org.apache.shiro.web.util.WebUtils; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class CustomRolesAuthorizationFilter extends AuthorizationFilter { @Override protected boolean isAccessAllowed(ServletRequest req, ServletResponse resp, Object o) throws Exception { Subject subject = getSubject(req, resp); String[] rolesArray = (String[]) o; if (rolesArray == null || rolesArray.length == 0) { //没有角色限制,有权限访问 return true; } for (int i = 0; i < rolesArray.length; i++) { if (subject.hasRole(rolesArray[i])) { //若当前用户是rolesArray中的任何一个,则有权限访问 return true; } } return false; } public static boolean isAjaxRequest(HttpServletRequest request) { String requestedWith = request.getHeader("x-requested-with"); if (requestedWith != null && requestedWith.equalsIgnoreCase("XMLHttpRequest")) { return true; } else { return false; } } /*** * 请求过滤的回调方法 */ @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException { Subject subject = getSubject(request, response); if (subject.getPrincipal() == null) { //未登录 if (isAjaxRequest((HttpServletRequest)request)) { response.setCharacterEncoding("UTF-8"); response.setContentType("application/json"); JsonResult jsonResult = new JsonResult(); jsonResult.setCode("401"); jsonResult.setMsg("登录认证失效,请重新登录!"); response.getWriter().write(JSONObject.toJSONString(jsonResult)); }else { saveRequestAndRedirectToLogin(request, response); } } else { //已经登陆,没有权限 String unauthorizedUrl = getUnauthorizedUrl(); if(isAjaxRequest((HttpServletRequest)request)) { response.setCharacterEncoding("UTF-8"); response.setContentType("application/json"); JsonResult jsonResult = new JsonResult(); jsonResult.setCode("401"); jsonResult.setMsg("您没有权限执行该操作"); response.getWriter().write(JSONObject.toJSONString(jsonResult)); }else { if (StringUtils.hasText(unauthorizedUrl)) { WebUtils.issueRedirect(request, response, unauthorizedUrl); } else { WebUtils.toHttp(response).sendError(HttpServletResponse.SC_UNAUTHORIZED); } } } return false; } }
2.2 CustomPermsAuthorizationFilter 类
import com.alibaba.fastjson.JSONObject; import com.zhuangzi.springboot1101.configurations.JsonResult; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.StringUtils; import org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter; import org.apache.shiro.web.util.WebUtils; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class CustomPermsAuthorizationFilter extends PermissionsAuthorizationFilter { @Override public boolean isAccessAllowed(ServletRequest req, ServletResponse resp, Object o) { Subject subject = getSubject(req, resp); String[] rolesArray = (String[]) o; if (rolesArray == null || rolesArray.length == 0) { //没有角色限制,有权限访问 return true; } for (int i = 0; i < rolesArray.length; i++) { if (subject.hasRole(rolesArray[i])) { //若当前用户是rolesArray中的任何一个,则有权限访问 return true; } } return false; } public static boolean isAjaxRequest(HttpServletRequest request) { String requestedWith = request.getHeader("x-requested-with"); if (requestedWith != null && requestedWith.equalsIgnoreCase("XMLHttpRequest")) { return true; } else { return false; } } /*** * 请求过滤的回调方法 */ @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException { Subject subject = getSubject(request, response); if (subject.getPrincipal() == null) { //未登录 if (isAjaxRequest((HttpServletRequest)request)) { response.setCharacterEncoding("UTF-8"); response.setContentType("application/json"); JsonResult jsonResult = new JsonResult(); jsonResult.setCode("401"); jsonResult.setMsg("登录认证失效,请重新登录!"); response.getWriter().write(JSONObject.toJSONString(jsonResult)); }else { saveRequestAndRedirectToLogin(request, response); } } else { //已经登陆,没有权限 String unauthorizedUrl = getUnauthorizedUrl(); if(isAjaxRequest((HttpServletRequest)request)) { response.setCharacterEncoding("UTF-8"); response.setContentType("application/json"); JsonResult jsonResult = new JsonResult(); jsonResult.setCode("401"); jsonResult.setMsg("您没有权限执行该操作"); response.getWriter().write(JSONObject.toJSONString(jsonResult)); }else { if (StringUtils.hasText(unauthorizedUrl)) { WebUtils.issueRedirect(request, response, unauthorizedUrl); } else { WebUtils.toHttp(response).sendError(HttpServletResponse.SC_UNAUTHORIZED); } } } return false; } }
顺便附上ShiroConfig配置类 及MyRealm类
import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.mgt.SecurityManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.servlet.Filter; import java.util.LinkedHashMap; import java.util.Map; @Configuration public class ShiroConfig { private static final Logger logger = LoggerFactory.getLogger(ShiroConfig.class); /** * 注入自定义的realm * @return MyRealm */ @Bean // <bean id = 'myAuthRealm' class=> public MyRealm myAuthRealm() { MyRealm myRealm = new MyRealm(); logger.info("====myRealm注册完成====="); return myRealm; } /** * 注入安全管理器 * @return SecurityManager */ @Bean public SecurityManager securityManager() { // 将自定义realm加进来 DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(myAuthRealm()); logger.info("====securityManager注册完成===="); return securityManager; } @Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { // 定义shiroFactoryBean ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean(); // 设置自定义的securityManager shiroFilterFactoryBean.setSecurityManager(securityManager); Map<String, Filter> filters = new LinkedHashMap<>(); filters.put("roles", new CustomRolesAuthorizationFilter()); filters.put("perms",new CustomPermsAuthorizationFilter()); shiroFilterFactoryBean.setFilters(filters); // 设置默认登录的url,身份认证失败会访问该url shiroFilterFactoryBean.setLoginUrl("/login"); // 设置成功之后要跳转的链接 shiroFilterFactoryBean.setSuccessUrl("/success"); // 设置未授权界面,权限认证失败会访问该url shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized"); // LinkedHashMap是有序的,进行顺序拦截器配置 Map<String,String> filterChainMap = new LinkedHashMap<>(); // 配置可以匿名访问的地址,可以根据实际情况自己添加,放行一些静态资源等,anon表示放行 filterChainMap.put("/images/**", "authc"); //在实际应用中, 这个身份拦截大致是:filterChainMap.put("/admin/**", "authc"); //即所有/admin/开头的url都必须 登陆 成功才有基本的资格访问页面 // “/user/student” 开头的需要角色认证,是“admin”才允许 filterChainMap.put("/user/student/**", "roles[学生]"); //测试,先用一个非学生角色登陆,访问, 应该是无权访问 // 再使用一个学生角色访问, 应该是可以访问 // “/user/teacher” 开头的需要权限认证,是“user:create”才允许 filterChainMap.put("/user/teacher*/**", "perms[\"user:add\"]"); // 不同的角色可以有相同的权限,只有此权限就可以访问, 不一定是必须是什么角色 // user:* : 匹配 user : 任意值 // user:add: 匹配 user:add filterChainMap.put("/user/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap); logger.info("====shiroFilterFactoryBean注册完成===="); return shiroFilterFactoryBean; } }
import com.zhuangzi.springboot1101.entity.Users; import com.zhuangzi.springboot1101.service.UsersService; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import javax.annotation.Resource; //Realm : 领域 // 本实中实现了 有什么权限(包含 角色及权限, 身份认证) public class MyRealm extends AuthorizingRealm { @Resource private UsersService usersService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { // 获取用户名 String username = (String) principalCollection.getPrimaryPrincipal(); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); //授权信息 // 给该用户设置角色,角色信息存在t_role表中取 authorizationInfo.setRoles(usersService.getRoles(username)); System.out.println(usersService.getRoles(username)); // 给该用户设置权限,权限信息存在t_permission表中取 authorizationInfo.setStringPermissions(usersService.getPermissions(username)); System.out.println("权限是:" + usersService.getPermissions(username)); return authorizationInfo; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { // 根据token获取用户名,如果您不知道该该token怎么来的,先可以不管,下文会解释 String username = (String) authenticationToken.getPrincipal(); // 根据用户名从数据库中查询该用户 Users users = usersService.getByUsername(username); if(users != null) { // 把当前用户存到session中 SecurityUtils.getSubject().getSession().setAttribute("user", users); // 传入用户名和密码进行身份认证,并返回认证信息 AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(users.getUsername(), users.getUserpwd(), "myRealm"); return authcInfo; } else { return null; } } }