引入: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. BZOJ1208 HNOI2004 宠物收养所 【非旋转Treap】

    BZOJ1208 HNOI2004 宠物收养所 Description 最近,阿Q开了一间宠物收养所.收养所提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物.每个领养者都希望领养到自己满意的 ...

  2. 语义版本号(Semantic Versioning)

    版本号格式不陌生吧,.NET 传统的版本号格式类似这样 1.5.1254.0.本文将推荐一种新的版本号格式——语义版本号,格式类似这样 1.4.6-beta.我推荐语义版本号是因为这样的版本号自包含语 ...

  3. Unicode字符转换成字符串

    /*** * Unicode字符转换成字符串 * @param str * Unicode字符 * @return * String * * @author WXW */ public static ...

  4. vector 中的clear()

    为什么clear之后,还是输出fdsafdsa.有什么办法可以真正清空之? 因为对于vector,clear并不真正释放内存(这是为优化效率所做的事),clear实际所做的是为vector中所保存的所 ...

  5. [Luogu4631][APIO2018] Circle selection 选圆圈

    Luogu 题目描述 在平面上,有 \(n\) 个圆,记为 \(c_1, c_2,...,c_n\) .我们尝试对这些圆运行这个算法: \(1\).找到这些圆中半径最大的.如果有多个半径最大的圆,选择 ...

  6. delete和truncate操作

    SQL> --查询表的结构SQL> desc student; 名称 是否为空? 类型 ----------------------------------------- -------- ...

  7. simulink pi的方法产生锁相环

    pi方法就是比例积分方法,关于pi方法介绍参考http://www.elecfans.com/dianzichangshi/20120909287851.html 锁相环pi方法原理参考http:// ...

  8. Nomad 了解

    Introduction to Nomad Welcome to the intro guide to Nomad! This guide is the best place to start wit ...

  9. CDN初学搭建(ats)

    CDN初学搭建(ats) ats trafficserver squid 一. CDN初学搭建 准备vagrant virtualbox 内部环境测试所需包 一.vagrant创建启动虚拟机 1 mk ...

  10. mysql设置合适的索引长度

    理想的索引: 相对于写操作来说,表查询很频繁的表建立索引 字段区分度高 长度小(合适的长度,不是越小越好) 尽量能够覆盖常用字段 这些条件综合起来才能够达到最优索引,本次我们着重聊一下建立合适长度的索 ...