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