引入:https://blog.csdn.net/catoop/article/details/69210140

本文基于Shiro权限注解方式来控制Controller方法是否能够访问。 
例如使用到注解: 
@RequiresPermissions 来控制是否有对应权限才可以访问 
@RequiresUser 来控制是否存在用户登录状态才可以访问

想了解Shiro是如何通过注解来控制权限的,可以查看源码 AopAllianceAnnotationsAuthorizingMethodInterceptor ,其构造方法中添加了几个对应的权限注解方法拦截器(这里不做详细阐述)。

用户在请求使用这些注解方式控制的方法时,如果没有通过权限校验。Shiro 会抛出如下两组类型的异常。

登录认证类异常 UnauthenticatedException.class, AuthenticationException.class 
权限认证类异常 UnauthorizedException.class, AuthorizationException.class 
(每个具体的异常对应哪个注解,大家查看源码了解一下)

言归正传,直接上代码,通过代码来说明本文目的 “做Get和Post请求的时候,如果请求的URL是被注解权限控制的,在没有权限或者登陆失效的情况下,如果以正确方式的返回结果(如果用户没有登录,大多数都是直接跳转到登录页面了)”。

由于项目前端框架设定,如新增一个用户,先跳转新增用户页面,然后去保存用户信息,跳转新增用户页面是get请求,保存用户信息是Post请求。

实现如下:

通过一个 BaseController 来统一处理,然后被其他 Controller 继承即可,对于JSON和页面跳转,我们只需要做一个Ajax判断处理即可。

代码如下:

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Map.Entry;
import java.util.stream.Collectors; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.BeanMap;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ExceptionHandler; import com.zfull.commons.result.QueryResult;
import com.zfull.commons.web.vo.ReturnJsonVO;
import com.zfull.commons.web.vo.ShiroAccountVO;
import com.zfull.facade.authority.dto.BzMenuDTO;
import com.zfull.facade.authority.query.BzMenuQuery;
import com.zfull.facade.authority.service.BzMenuService; import net.sf.json.JSONArray; /**
* 基础Controller
* @ClassName: BaseController
* @Description: TODO
* @author OnlyMate
* @Date 2018年4月11日 下午2:30:00
*
*/
public class BaseController {
protected Logger log = LoggerFactory.getLogger(this.getClass()); protected final static String REDIRECT_LOGIN = "redirect:/login"; @Autowired
private BzMenuService menuService; // 右侧功能菜单
public String menuRight(String urlstr) {
String parMenuId = menuService.findMenuByAction(urlstr).getResults().get(0).getMenuId();
ShiroAccountVO currShiroUser = getCurrentUser();
String[] roleIds = currShiroUser.getRoleIds().split(",");// 当前登录用户所属角色
// 右侧菜单
BzMenuQuery menuQuery = new BzMenuQuery ();
menuQuery.setParentId(parMenuId);
menuQuery.setRoleIds(Arrays.asList(roleIds).stream().map(s -> Integer.parseInt(s.trim())).collect(Collectors.toList()));
QueryResult<BzMenuDTO> source = menuService.findMenuList(menuQuery);
StringBuilder htmls = new StringBuilder();
String menuids = "";
if (source != null && source.getResults().size() > 0) {
for (BzMenuDTO entity : source.getResults()) {
if (menuids.indexOf(entity.getMenuId()) > -1) {
continue;
}
menuids += entity.getMenuId() + ",";
if (entity.getFunction().contains("#")) {
/*htmls.append(
" <a href='" + entity.getMenuengname() + "'data-backdrop='static' data-toggle='modal'>");
htmls.append("<i class='" + entity.getIcon() + "'></i> ");
htmls.append(entity.getMenuname() + "</a>");*/
}else {
htmls.append(" <button class='btn' onclick='" + entity.getFunction() + "' >");
htmls.append("<i class='"+entity.getIcon()+"'></i>");
htmls.append("<span>"+entity.getMenuName() + "</span></button>");
}
}
}
htmls.append(" <input type='hidden' id='chkAction' name='chkAction' value='" + urlstr + "' />");
return htmls.toString();
} public ShiroAccountVO getCurrentUser() {
Subject subject = SecurityUtils.getSubject();
return (ShiroAccountVO) subject.getPrincipal();
} public String searchParams(Object obj) {
BeanMap map = new BeanMap(obj);
StringBuilder searchParams = new StringBuilder();
for (Entry<Object, Object> entry : map.entrySet()) {
if (!"class".equals(entry.getKey()) && !"pageSize".equals(entry.getKey()) && !"flag".equals(entry.getKey())
&& !"pageNum".equals(entry.getKey()) && entry.getValue() != null) {
searchParams.append(entry.getKey());
searchParams.append("=");
searchParams.append(entry.getValue());
searchParams.append("&");
}
}
return searchParams.toString();
}
/*********************** 以下是重点 *************************/
/**
* 登录认证异常(这个异常基本没有用,一般登录那里做了处理)
* @Title: authenticationException
* @Description: TODO
* @Date 2018年4月11日 下午2:19:06
* @author OnlyMate
* @param request
* @param response
* @return
*/
@ExceptionHandler({ UnauthenticatedException.class, AuthenticationException.class })
public String authenticationException(HttpServletRequest request, HttpServletResponse response) {
if (isAjaxRequest(request)) {
// 输出JSON
ReturnJsonVO returnJson = new ReturnJsonVO();
returnJson.setStatus(ReturnJsonVO.SUBMIT_FAILURE); // 提交失败 1
String message = "当前登录用户无该权限";
returnJson.setMessage(message);
writeJson(returnJson, response);
return null;
} else {
return "redirect:/login";
}
} /**
* 权限异常
* @Title: authorizationException
* @Description: TODO
* @Date 2018年4月11日 下午2:19:18
* @author OnlyMate
* @param request
* @param response
* @return
*/
@ExceptionHandler({ UnauthorizedException.class, AuthorizationException.class })
public String authorizationException(HttpServletRequest request, HttpServletResponse response) {
if (isAjaxRequest(request)) {
// 输出JSON
ReturnJsonVO returnJson = new ReturnJsonVO();
returnJson.setStatus(ReturnJsonVO.SUBMIT_FAILURE); // 提交失败 1
String message = "当前登录用户无该权限";
returnJson.setMessage(message);
writeJson(returnJson, response);
return null;
} else {
return "redirect:/unauthor";
}
} /**
* 输出JSON
* @Title: writeJson
* @Description: TODO
* @Date 2018年4月11日 下午2:18:10
* @author OnlyMate
* @param returnJson
* @param response
*/
private void writeJson(ReturnJsonVO returnJson, HttpServletResponse response) {
PrintWriter out = null;
try {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
out = response.getWriter();
out.write(JSONArray.fromObject(returnJson).toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
out.close();
}
}
} /**
* 是否是Ajax请求
* @Title: isAjaxRequest
* @Description: TODO
* @Date 2018年4月11日 下午2:19:31
* @author OnlyMate
* @param request
* @return
*/
public static boolean isAjaxRequest(HttpServletRequest request) {
String requestedWith = request.getHeader("x-requested-with");
if (requestedWith != null && requestedWith.equalsIgnoreCase("XMLHttpRequest")) {
return true;
} else {
return false;
}
}
}

下面是一个普通的 Controller,继承了BaseController

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody; import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import com.zfull.commons.enums.basic.RoleLevelEnum;
import com.zfull.commons.result.QueryResult;
import com.zfull.commons.result.Result;
import com.zfull.commons.result.SingleResult;
import com.zfull.commons.security.CipherTools;
import com.zfull.commons.utils.DateUtil;
import com.zfull.commons.web.utils.JsonMapper;
import com.zfull.commons.web.vo.ReturnJsonVO;
import com.zfull.commons.web.vo.ShiroAccountVO;
import com.zfull.facade.authority.dto.BzOperToRole;
import com.zfull.facade.authority.dto.BzOperatorDTO;
import com.zfull.facade.authority.dto.BzRoleDTO;
import com.zfull.facade.authority.query.BzOperatorQuery;
import com.zfull.facade.authority.query.BzRoleQuery;
import com.zfull.facade.authority.service.BzOperatorMchtService;
import com.zfull.facade.authority.service.BzRoleService;
import com.zfull.facade.authority.vo.BzOperatorVO;
import com.zfull.web.common.BaseController; import net.sf.json.JSONArray; @Controller
@RequestMapping(value=BzOperatorMchtController.PARENT_URL)
public class BzOperatorMchtController extends BaseController{
protected final static String PARENT_URL = "/permission/operatormcht";
private static JsonMapper mapper = JsonMapper.nonDefaultMapper(); @Autowired
private BzOperatorMchtService operatorMchtService;
@Autowired
private BzRoleService roleService; /**
* 用户列表
* @Title: index
* @Description: TODO
* @Date: 2018年3月26日 下午2:34:49
* @author: OnlyMate
* @throws:
* @param request
* @param query
* @return
*/
@RequiresPermissions(value="operatormcht.index")
@RequestMapping(method = RequestMethod.GET)
public String index(HttpServletRequest request, Model model, BzOperatorQuery query) {
ReturnJsonVO returnJson = new ReturnJsonVO();
returnJson.setStatus(ReturnJsonVO.SUBMIT_FAILURE); //提交失败 1
String message = "查询用户首页出错";
// 获取当前操作员信息
ShiroAccountVO currShiroUser = getCurrentUser(); QueryResult<BzOperatorVO> result = new QueryResult<BzOperatorVO>();
try {
// TODO 按照登录用户去筛选数据,查询当前的商户信息 result = operatorMchtService.queryOperatorList(query);
if(result.isSuccess()) {
message = "查询用户首页成功";
returnJson.setStatus("0");
returnJson.setData(JSON.toJSONString(result));
}else {
message = "查询用户首页失败";
}
} catch (Exception e) {
message = "查询用户首页出错";
log.error(message);
e.printStackTrace();
}finally {
returnJson.setMessage(message);
log.info("系统日志:登录名={},操作员={},ip={},日期={},操作{}的{}方法-{}",
currShiroUser.getOperId(),currShiroUser.getOperName(),currShiroUser.getLoginIP(),
              DateUtil.currentDatetime(),"BzOperatorMchtController","index",message);
} model.addAttribute("roleinfos", roleService.findRoleList(new BzRoleQuery()));
model.addAttribute("source", result);
model.addAttribute("query", query);
model.addAttribute("menuRight", menuRight(PARENT_URL));
model.addAttribute("searchParams", searchParams(query));
model.addAttribute("currentOperId", currShiroUser.getOperId()); return PARENT_URL + "/index";
} /**
* 用户详情
* @Title: detail
* @Description: TODO
* @Date: 2018年3月26日 下午2:35:01
* @author: OnlyMate
* @throws:
* @param request
* @param operId
* @return
*/
@ResponseBody
@RequiresPermissions(value="operatormcht.detail")
@RequestMapping(value="/detail", method = RequestMethod.POST)
public ReturnJsonVO detail(HttpServletRequest request, String operId) {
ReturnJsonVO returnJson = new ReturnJsonVO();
returnJson.setStatus(ReturnJsonVO.SUBMIT_FAILURE); //提交失败 1
String message = "查询用户详情出错";
// 获取当前操作员信息
// ShiroAccountVO currShiroUser = getCurrentUser();
try {
if(StringUtils.isBlank(operId)) {
message = "传入参数有误";
returnJson.setMessage(message);
return returnJson;
}
SingleResult<BzOperatorDTO> result = operatorMchtService.findByOperId(operId);
if(result.isSuccess()) {
returnJson.setStatus("0");
returnJson.setData(JSON.toJSONString(result.getResult()));
message = "查询用户详情成功";
}else {
message = "查询用户详情失败";
}
} catch (Exception e) {
message = "查询用户详情出错";
log.error(message);
e.printStackTrace();
}finally {
returnJson.setMessage(message);
}
return returnJson;
} /**
* 跳转新增用户界面
* @Title: addView
* @Description: TODO
* @Date: 2018年4月2日 上午1:45:45
* @author: OnlyMate
* @throws:
* @param model
* @return
*/
@RequiresPermissions(value = "operatormcht.addView")
@RequestMapping(value = "/addView", method = RequestMethod.GET)
public String addView(Model model) {
ReturnJsonVO returnJson = new ReturnJsonVO();
returnJson.setStatus(ReturnJsonVO.SUBMIT_FAILURE); // 提交失败 1
String message = "跳转新增用户页面出错";
try {
//TODO 查询机构和商户信息 message = "跳转新增用户页面成功";
returnJson.setStatus("0");
returnJson.setData(JSON.toJSONString(""));
} catch (Exception e) {
message = "跳转新增用户页面出错";
log.error(message);
e.printStackTrace();
} finally {
returnJson.setMessage(message);
}
return PARENT_URL + "/add";
} /**
* 保存用户
* @Title: add
* @Description: TODO
* @Date: 2018年3月26日 下午2:35:45
* @author: OnlyMate
* @throws:
* @param request
* @param dto
* @return
*/
@ResponseBody
@RequiresPermissions(value="operatormcht.add")
@RequestMapping(value="/add", method = RequestMethod.POST)
public String add(HttpServletRequest request, BzOperatorDTO dto) {
ReturnJsonVO returnJson = new ReturnJsonVO();
returnJson.setStatus(ReturnJsonVO.SUBMIT_FAILURE); //提交失败 1
String message = "用户新增出错";
// 获取当前操作员信息
ShiroAccountVO currShiroUser = getCurrentUser(); BzOperatorQuery query = new BzOperatorQuery();
boolean flag = Boolean.TRUE;
try {
if(StringUtils.isNotBlank(dto.getOperId()) &&
StringUtils.isNotBlank(dto.getBindPhone()) &&
StringUtils.isNotBlank(dto.getBindEmail())) {
query.setLoginName(dto.getOperId());
if(flag && !checkLoginName(query)) {
flag = Boolean.FALSE;
message = "用户名已存在";
}
query.setLoginName(dto.getBindPhone());
if(flag && !checkLoginName(query)){
flag = Boolean.FALSE;
message = "绑定手机号已存在";
}
query.setLoginName(dto.getBindEmail());
if(flag && !checkLoginName(query)) {
flag = Boolean.FALSE;
message = "绑定邮箱号已存在";
}
if(flag) {
dto.setPasswd("a94d5cd0079cfc8db030e1107de1addd1903a01b");
dto.setOnlineFlag("OFFLINE");
dto.setInitPasswd("INIT");
dto.setCreateFlag("MANUAL");
dto.setLoginCount(0);
dto.setLastTime(new Date());
Result result = operatorMchtService.insertOperator(dto);
if(result.isSuccess()) {
message = "用户新增成功";
returnJson.setStatus("0");
}else {
message = "用户新增失败";
}
}
}else {
message = "传入参数有误";
}
} catch (Exception e) {
message = "用户新增出错";
log.error(message);
e.printStackTrace();
}finally {
returnJson.setMessage(message);
log.info("系统日志:登录名={},操作员={},ip={},日期={},操作{}的{}方法-{}",
currShiroUser.getOperId(),currShiroUser.getOperName(),currShiroUser.getLoginIP(),
              DateUtil.currentDatetime(),"BzOperatorMchtController","add",message);
}
return JSONArray.fromObject(returnJson).toString();
} /**
* 跳转用户编辑页面
* @Title: editView
* @Description: TODO
* @Date: 2018年4月2日 上午10:44:10
* @author: OnlyMate
* @throws:
* @param model
* @param query
* @return
*/
@RequiresPermissions(value = "operatormcht.editView")
@RequestMapping(value = "/editView", method = RequestMethod.GET)
public String editView(Model model, BzOperatorQuery query) {
ReturnJsonVO returnJson = new ReturnJsonVO();
returnJson.setStatus(ReturnJsonVO.SUBMIT_FAILURE); // 提交失败 1
String message = "跳转编辑用户页面出错"; BzOperatorDTO oper = new BzOperatorDTO(); try {
if (StringUtils.isBlank(query.getOperId())) {
message = "传入参数有误";
}else {
oper = operatorMchtService.findByOperId(query.getOperId()).getResult();
message = "跳转编辑用户页面成功";
returnJson.setStatus("0");
returnJson.setData(JSON.toJSONString(oper));
} } catch (Exception e) {
message = "跳转编辑用户页面出错";
log.error(message);
e.printStackTrace();
} finally {
returnJson.setMessage(message);
}
model.addAttribute("oper", oper);
return PARENT_URL + "/edit";
} /**
* 更新用户
* @Title: edit
* @Description: TODO
* @Date: 2018年3月26日 下午2:36:02
* @author: OnlyMate
* @throws:
* @param request
* @param dto
* @return
*/
@ResponseBody
@RequiresPermissions(value="operatormcht.edit")
@RequestMapping(value="/edit", method = RequestMethod.POST)
public String edit(HttpServletRequest request, BzOperatorDTO dto) {
ReturnJsonVO returnJson = new ReturnJsonVO();
returnJson.setStatus(ReturnJsonVO.SUBMIT_FAILURE); //提交失败 1
String message = "用户更新出错";
// 获取当前操作员信息
ShiroAccountVO currShiroUser = getCurrentUser(); BzOperatorQuery query = new BzOperatorQuery();
boolean flag = Boolean.TRUE;
try {
if(StringUtils.isNotBlank(dto.getOperId()) &&
StringUtils.isNotBlank(dto.getBindPhone()) &&
StringUtils.isNotBlank(dto.getBindEmail())) {
query.setOperId(dto.getOperId());
query.setLoginName(dto.getOperId());
if(flag && !checkLoginName(query)) {
flag = Boolean.FALSE;
message = "用户名已存在";
}
query.setLoginName(dto.getBindPhone());
if(flag && !checkLoginName(query)){
flag = Boolean.FALSE;
message = "绑定手机号已存在";
}
query.setLoginName(dto.getBindEmail());
if(flag && !checkLoginName(query)) {
flag = Boolean.FALSE;
message = "绑定邮箱号已存在";
}
if(flag) {
BzOperatorDTO oldOperator = operatorMchtService.findByOperId(dto.getOperId()).getResult();
dto.setOnlineFlag(oldOperator.getOnlineFlag());
dto.setInitPasswd(oldOperator.getInitPasswd());
dto.setCreateFlag(oldOperator.getCreateFlag());
dto.setLoginCount(oldOperator.getLoginCount());
dto.setLastTime(new Date());
Result result = operatorMchtService.updateOperator(dto);
if(result.isSuccess()) {
message = "用户更新成功";
returnJson.setStatus("0");
}else {
message = "用户更新失败";
}
}
}else {
message = "传入参数有误";
} } catch (Exception e) {
message = "用户更新出错";
log.error(message);
e.printStackTrace();
}finally {
returnJson.setMessage(message);
log.info("系统日志:登录名={},操作员={},ip={},日期={},操作{}的{}方法-{}",
currShiroUser.getOperId(),currShiroUser.getOperName(),currShiroUser.getLoginIP(),
                DateUtil.currentDatetime(),"BzOperatorMchtController","edit",message);
}
return JSONArray.fromObject(returnJson).toString();
}
}

未授权路径

/**
* 未授权页面
* @Title: unauthor
* @Description: TODO
* @Date 2018年4月11日 上午12:19:37
* @author OnlyMate
* @param request
* @param response
* @param model
* @return
*/
@RequestMapping(value = "/unauthor", method = RequestMethod.GET)
public String unauthor(HttpServletRequest request, HttpServletResponse response, Model model){
return "/unauthor";
}

未授权页面

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<c:set var="ctx" value="${pageContext.request.contextPath}" />
<!DOCTYPE HTML>
<head>
<link rel="stylesheet" href="${ctx}/static/lib/jquery-ztree/css/zTreeStyle.css" type="text/css" />
<link rel="stylesheet" href="${ctx}/static/lib/bootstrap/css/bootstrap.css">
<link rel="stylesheet" href="${ctx}/static/css/reset.css">
<link rel="stylesheet"
href="${ctx}/static/lib/jquery.mCustomScrollbar/jquery.mCustomScrollbar.css">
<link rel="stylesheet" href="${ctx}/static/css/index.css">
<link rel="stylesheet" href="${ctx}/static/css/main.css">
<link rel="stylesheet" href="${ctx}/static/css/style.css">
<link rel="stylesheet" href="${ctx}/static/img/splashy/splashy.css">
<link href="${ctx}/static/lib/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div class="main_con">
<div class="btn-actions">
<span style="color: red;font-size: 20px;">当前登录用户无该权限</span>
</div>
</div>
</body>
</html>

当我们使用 get方式去请求/permission/operatormcht/addView时,如果用户没有授权,则重定向"redirect:/unauthor"到unauthor.jsp页面。

效果如下:

当我们使用  post方式去请求/permission/operatormcht/edit时,如果用户没有授权,则会返回没有授权的JSON结果,而不是页面。

效果如下:

这样解决了,在shrio权限校验中,区分Get和Post请求以正确的方式去返回对应的信息,get返回没有授权的页面,post返回没有授权的Json信息。

Shiro 权限校验不通过时,区分GET和POST请求正确响应对应的方式的更多相关文章

  1. 类Shiro权限校验框架的设计和实现(2)--对复杂权限表达式的支持

    前言: 我看了下shiro好像默认不支持复杂表达式的权限校验, 它需要开发者自己去做些功能扩展的工作. 针对这个问题, 同时也会为了弥补上一篇文章提到的支持复杂表示需求, 特地尝试写一下解决方法. 本 ...

  2. fastDFS shiro权限校验 redis FreeMark页面静态化

    FastDFS是一个轻量级分布式文件系统,   使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传.下载等服务   FastDFS服务端有两个角色:跟踪器(tracker)和存储节点( ...

  3. 类Shiro权限校验框架的设计和实现

    前言: 之前简单集成了springmvc和shiro用于后台管理平台的权限控制, 设计思路非常的优美, 而且编程确实非常的方便和简洁. 唯一的不足, 我觉得配置稍有些繁琐. 当时我有个小想法, 觉得可 ...

  4. 用异提交时,后台通过校验规则文件,校验不通过时,跳转到INPUT视图时,前台显示错误信息的解决办法

    1.第一种: 最近项目使用了struts2的校验(其实我觉得后台校验,特别是struts的校验,完全可以放在其他地方处理,比如交给js或者业务逻辑),而且系统刚好还使用了extjs,此时问题出现了:假 ...

  5. Shiro实现用户对动态资源细粒度的权限校验

    前言 在实际系统应用中,普遍存在这样的一种业务场景,需要实现用户对要访问的资源进行动态权限校验. 譬如,在某平台的商家系统中,存在商家.品牌.商品等业务资源.它们之间的关系为:一个商家可以拥有多个品牌 ...

  6. Spring AOP 实现功能权限校验功能

    版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[-] 使用拦截器实现未登录时跳转到登录界面的功能 1 拦截器SecurityInterceptor 2spring-mvcxml拦 ...

  7. 基于Spring Aop实现类似shiro的简单权限校验功能

    在我们的web开发过程中,经常需要用到功能权限校验,验证用户是否有某个角色或者权限,目前有很多框架,如Shiro Shiro有基于自定义登录界面的版本,也有基于CAS登录的版本,目前我们的系统是基于C ...

  8. 【SpringBoot技术专题】「权限校验专区」Shiro整合JWT授权和认证实现

    本章介绍一下常用的认证框架Shiro结合springboot以及集合jwt快速带您开发完成一个认证框架机制. Maven配置依赖 <dependency> <groupId>o ...

  9. Apache shiro之权限校验流程

    从张开涛blog学习后整理:http://jinnianshilongnian.iteye.com/blog/2018398 图片原图比较大,建议将图片在新的选项卡打开后100%大小浏览 在权限校验中 ...

随机推荐

  1. 使用LinkedBlockingQueue来实现生产者消费者的例子

    工作中,经常有将文件中的数据导入数据库的表中,或者将数据库表中的记录保存到文件中.为了提高程序的处理速度,可以设置读线程和写线程,这些线程通过消息队列进行数据交互.本例就是使用了LinkedBlock ...

  2. .NET/C# 使用 Span 为字符串处理提升性能

    .NET Core 2.1 和 C# 7.2 带来了 Span 的原生支持,原本需要使用不安全代码操作的内存块现在可以使用安全的方式来完成.此前在性能和稳定性上需要有所取舍,而现在可以兼得了. 简单的 ...

  3. 如何实现一个可以用 await 异步等待的 Awaiter

    .NET 和 C# 共同给我们带来的 async/await 异步编程模型(TAP)用起来真的很爽.为了实现异步等待,我们只需要在一切能够能够异步等待的方法前面加上 await 即可.能够异步等待的最 ...

  4. Adobe Acrobat 9 Pro破解方法

    首先安装Adobe Acrobat 9 Pro,默认安装在C盘. 如果你的系统盘是C盘,那么就删除:c:/Documents and Settings/All Users/Application Da ...

  5. Thinkphp 下 MySQL group by 接count 获得条数方法

    比如 下面的语句 , 用于分组统计 select count(*) from es_diabetes where uid=43658 GROUP BY uniques 结果明显不是我们想要得,为什么呢 ...

  6. hashids 了解

    用于隐藏真实的id 原理是从数字经过一个加盐(salted)算法产生一个哈希(hash)字符串.这样算法就是通过混淆使结果具有不可预测性,而唯一性依然由数字本身来达成,从而得到(类似 youtube ...

  7. 给DB2增加删除字段二三事

    加字段用这个,CS.TG表名,LINE2_TYPE字段名,CHAR(1)字段类型 ALTER TABLE CS.TG ADD COLUMN LINE2_TYPE CHAR(1); 要是加错了用以下语句 ...

  8. 【转】利用 Apache JMeter 测试 WebSphere 性能

    如果您预算紧张并且时间紧迫 —— 或者即使您不是这样 —— 那么,您可能希望考虑使用 JMeter 来对 Web 和其他应用程序进行压力测试.IBM 的 Greg Herringer 详细描述他使用这 ...

  9. 一行代码搞定 FTP 服务

    环境搭建: python windows/linux pip install pyftpdlib (安装失败请到这里下载:https://pypi.python.org/pypi/pyftpdlib/ ...

  10. Resource interpreted as Document but transferred with MIME type application/json laravel异常请求返回警告

    一般情况下,laravel在方法里可以向前端返回数组格式 return [], 框架可以自动将数组转成JSON字符串返回,但浏览器会报MIME类型警告, 如是做APP接口可以忽视该警告: 但在前端aj ...