在前后端分離的應用中,需要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;
}
}
}