在前后端分離的應用中,需要shiro授權(quán)失敗時,返回json格式數(shù)據(jù), 如下是在springboot應用中,前端ajax請求, shiro授權(quán)失敗,返回json數(shù)據(jù)的應用實例
1, 在ShiroFilterFactoryBean類中增加如下兩行代碼:
2, 當然同時需要定義兩個角色和權(quán)限返回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) { //沒有角色限制,有權(quán)限訪問 return true; } for (int i = 0; i < rolesArray.length; i++) { if (subject.hasRole(rolesArray[i])) { //若當前用戶是rolesArray中的任何一個,則有權(quán)限訪問 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; } } /*** * 請求過濾的回調(diào)方法 */ @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 { //已經(jīng)登陸,沒有權(quán)限 String unauthorizedUrl = getUnauthorizedUrl(); if(isAjaxRequest((HttpServletRequest)request)) { response.setCharacterEncoding("UTF-8"); response.setContentType("application/json"); JsonResult jsonResult = new JsonResult(); jsonResult.setCode("401"); jsonResult.setMsg("您沒有權(quán)限執(zhí)行該操作"); 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) { //沒有角色限制,有權(quán)限訪問 return true; } for (int i = 0; i < rolesArray.length; i++) { if (subject.hasRole(rolesArray[i])) { //若當前用戶是rolesArray中的任何一個,則有權(quán)限訪問 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; } } /*** * 請求過濾的回調(diào)方法 */ @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 { //已經(jīng)登陸,沒有權(quán)限 String unauthorizedUrl = getUnauthorizedUrl(); if(isAjaxRequest((HttpServletRequest)request)) { response.setCharacterEncoding("UTF-8"); response.setContentType("application/json"); JsonResult jsonResult = new JsonResult(); jsonResult.setCode("401"); jsonResult.setMsg("您沒有權(quán)限執(zhí)行該操作"); 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(); // 設(shè)置自定義的securityManager shiroFilterFactoryBean.setSecurityManager(securityManager); Map<String, Filter> filters = new LinkedHashMap<>(); filters.put("roles", new CustomRolesAuthorizationFilter()); filters.put("perms",new CustomPermsAuthorizationFilter()); shiroFilterFactoryBean.setFilters(filters); // 設(shè)置默認登錄的url,身份認證失敗會訪問該url shiroFilterFactoryBean.setLoginUrl("/login"); // 設(shè)置成功之后要跳轉(zhuǎn)的鏈接 shiroFilterFactoryBean.setSuccessUrl("/success"); // 設(shè)置未授權(quán)界面,權(quán)限認證失敗會訪問該url shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized"); // LinkedHashMap是有序的,進行順序攔截器配置 Map<String,String> filterChainMap = new LinkedHashMap<>(); // 配置可以匿名訪問的地址,可以根據(jù)實際情況自己添加,放行一些靜態(tài)資源等,anon表示放行 filterChainMap.put("/images/**", "authc"); //在實際應用中, 這個身份攔截大致是:filterChainMap.put("/admin/**", "authc"); //即所有/admin/開頭的url都必須 登陸 成功才有基本的資格訪問頁面 // “/user/student” 開頭的需要角色認證,是“admin”才允許 filterChainMap.put("/user/student/**", "roles[學生]"); //測試,先用一個非學生角色登陸,訪問, 應該是無權(quán)訪問 // 再使用一個學生角色訪問, 應該是可以訪問 // “/user/teacher” 開頭的需要權(quán)限認證,是“user:create”才允許 filterChainMap.put("/user/teacher*/**", "perms[\"user:add\"]"); // 不同的角色可以有相同的權(quán)限,只有此權(quán)限就可以訪問, 不一定是必須是什么角色 // 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 : 領(lǐng)域 // 本實中實現(xiàn)了 有什么權(quán)限(包含 角色及權(quán)限, 身份認證) public class MyRealm extends AuthorizingRealm { @Resource private UsersService usersService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { // 獲取用戶名 String username = (String) principalCollection.getPrimaryPrincipal(); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); //授權(quán)信息 // 給該用戶設(shè)置角色,角色信息存在t_role表中取 authorizationInfo.setRoles(usersService.getRoles(username)); System.out.println(usersService.getRoles(username)); // 給該用戶設(shè)置權(quán)限,權(quán)限信息存在t_permission表中取 authorizationInfo.setStringPermissions(usersService.getPermissions(username)); System.out.println("權(quán)限是:" + usersService.getPermissions(username)); return authorizationInfo; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { // 根據(jù)token獲取用戶名,如果您不知道該該token怎么來的,先可以不管,下文會解釋 String username = (String) authenticationToken.getPrincipal(); // 根據(jù)用戶名從數(shù)據(jù)庫中查詢該用戶 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; } } }