shiro权限管理(二)
本篇主要是把权限控制在rest接口端,欢迎圈错,共同学习。
采用maven的整体构造,提供sql和ws模块。(maven+spring+mybatis+Xmemcached+jetty)。
贴图为部分代码,文末附上整个项目源码。
一、图示流程及效果图
1.先看数据库表关系和内容
2.从上图所知道
用户名为table的用户 ,角色为管理员 , 拥有user-select 权限;
用户名为table1的用户, 角色为一般用户 ,不拥有 user-select权限;
3.用户名table登录
登录之后获取角色id和认证头bearer 去访问user-select 权限对应的接口url
正常访问得到数据的情况
4.用户名table1登录 没有权限访问该接口的情况
5.总结
1.该版权限控制在rest接口上,效果如上述所示。这只是简单的实例,根据具体的项目需要丰富表内容。
2.前台调用后台提供接口,需先访问登录接口,获取bearer认证头和角色ID作为参数传入到每个接口。
3.认证头为缓存实现为5分钟,避免了获取一次,永久访问的情况。
二、流程详解
1.采用maven架构搭建整个工程,主要采用spring+mybatis配置后台,从数据库封装一个查询接口,提供一个restful
具体代码略,会提供rest接口的自然懂……
rest接口步骤: 测试工具:
1.dto firefox插件(restClient/Httprest)
2.dao secureCRT 后台查看工具(本地测试采用控制台)
3.daoimpl
4.dto.xml
5.ws
与一般的底层增删改查一致,就是ws层根据实际项目需要返回,一般返回json或者xml格式的数据
2.搭建好之后,集成memcached,采用客户端为xmemcached(详见memcached客户端使用的三种方式)
3.集成shiro
1.web.xml中加入shiro过滤器,拦截rest下的所有url
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/rest/*</url-pattern>
</filter-mapping>
2.把请求的url交给shiro之后,由于我们要把权限控制在接口上,shiro.xml相应变化;
每次请求来交给一个自定义过滤器,除开登录的url,拦截web.xml中过来的所有请求。
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="filters">
<util:map>
<entry key="custom" value-ref="customFilter"/>
</util:map>
</property>
<property name="filterChainDefinitions">
<value>
/rest/login = anon
/** = custom
</value>
</property>
</bean>
<!-- 自定义过滤器 -->
<bean id="customFilter" class="com.sss.shiro.CustomFilter"/>
3.请求交给自定义过滤器
1. 自定义过滤器继承AuthenticatingFilter,此时会强制重写createToken和onAccessDenied两个方法。
A. createToken :表示创建一个用户身份验证的一个令牌,在其shiro底层有两个拦截器继承了AuthenticatingFilter分别是BasicHttpAuthenticationFilter和FormAuthenticationFilter这两个同时实现了createToken方法,createToken方法里面是通过每次代入用户名和密码和把请求的request和response放入进去生成即可(需要了解的可以仔细看看源码)。我这里用这个令牌的目的就是替换底层实现的这一套,每次在登陆的接口里面设置,登陆成功之后随机生成一个UUID作为认证的bearer。
/***
* 创建一个令牌
* 每次请求的信息封装在token里面,在realm中的认证方法中获取和比对
*/
@Override
protected AuthenticationToken createToken(ServletRequest request,
ServletResponse response) throws Exception {
String name = request.getParameter("name");
String bearer = request.getParameter("bearer");
String roleId = request.getParameter("roleId");
return new CustomToken(name, bearer,roleId);
}
认证的token中主要的一个部分bearer是在登录接口中放入的随机UUID
user.setPwd(encryptPwd);
user.setIp(ip);
String bearer = UUID.randomUUID().toString();
user.setBearer(bearer);
user.setRoleId(roleId);
memcached.addCache("bearer", user, 5);
memcached.addCache("permissionList", permissions, 1);
这是登录接口返回的user 。 缓存中放入认证头bearer,其目的就是客户端和shiro的realm中的认证方法里拿到的realm进行比对。避免一次请求,永久访问。
权限放入缓存,是方便查询,在shiro的realm中授权方法里面比对该登录的用户是否有访问该接口的权限,先从缓存里取,加快查询速度,缓存失效拿不到再通过
roleId查询数据中比对之后放入缓存。
B.onAccessDenied:表示当访问拒绝时是否已经处理了;如果返回true表示需要继续处理;如果返回false表示该拦截器实例已经处理了,将直接返回即可。
也是该自定义过滤器的入口,主要判断认证信息是否存在,存在即交给处理方法进行处理。
@Override
protected boolean onAccessDenied(ServletRequest request,
ServletResponse response) throws Exception {
logger.info("访问控制拦截器中传入参数:{}",request.getParameterMap());
String bearer = request.getParameter("bearer");
boolean isLogin = false;
if (StringUtils.isNotEmpty(bearer)) {
isLogin = executeLogin(request, response);
}
return isLogin;
}
B-1.此处处理涉及了一个executeLogin方法得到当前的用户,通过subject.login(token);交给realm中的认证方法来认证,由于错误信息不友好,自定义executeLogin方法 覆盖掉它。
B-2.若认证失败给接口提示,若认证成功,通过boolean isPermitted = subject.isPermitted(httpRequest.getRequestURI());把当前访问的rest接口路径交给realm中的授权方法判断是否有该接口的访问权限。有访问权限出数据,没有就给提示。
B-3.通过subject.login(token) 这里token就是自定义的token,通过createToken创建。通过shiro的realm中的认证方法可以知道,当前认证接受的token值为AuthenticationToken。所以我们这定义的token类就去实现它。属性若干,根据实际需要定义。
public class CustomToken implements AuthenticationToken {
private static final long serialVersionUID = 1L;
private String username;
private String roleId;
private String bearer;
private User user;
public CustomToken(String username,String clientDigest,String roleId){
this.bearer = clientDigest;
this.username = username;
this.roleId = roleId;
}
public CustomToken(User user){
this.user= user;
}
B-4.其中的roleId是需要的。
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
logger.info("enter---shiro的认证方法");
CustomToken CustomToken = (CustomToken) token;
String bearer = CustomToken.getBearer();
String roleId = CustomToken.getRoleId();
User user = null;
try {
user = (User) memcachedUtils.findCache("bearer");
} catch (Exception e) {
logger.debug("缓存读取认证头失败:{}", user);
return null;
}
// 然后进行客户端消息摘要和服务器端消息摘要的匹配
SimpleAuthenticationInfo aa = new SimpleAuthenticationInfo(roleId,
user.getBearer(), getName());
return aa;
}
此处主要从登陆接口中放入的缓存头,来获取,如果有比对认证(也可以在此处通过用户名比对一次密码),认证之后返回这个认证信息,带入orderId.
认证通过之后,在执行方法里面判断是否有权限访问该url
boolean isPermitted = subject.isPermitted(httpRequest.getRequestURI());
if(!isPermitted){
sendChallenge(response, "该用户没有权限访问,请联系管理员用户",null);
return false;
}
通过isPermitted进入到realm的授权方法
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
// 先读取缓存数据,再通过roleId查询数据加入缓存
//此处的授权参数就是接口带入的roleId,以便缓存失效时重新获取数据库中的权限集合
logger.info("授权参数:{}", principals);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
Set<String> permissions = new HashSet<>();
try {
if (memcachedUtils.findCache("permissionList") == null) {
logger.debug("从数据库读取");
//通过roleId来读取权限集合
String roleId = principals.toString();
Map<String, Object> whereMap = new HashMap<String, Object>();
whereMap.put("roleId", roleId);
List<Map<String, Object>> allPermissUrl = userDao
.selectPermissionByName(whereMap);
for (Map<String, Object> map : allPermissUrl) {
permissions.add(dom4jReadXML(map.get("permission_name")
.toString()));
}
} else {
logger.debug("从缓存信息读取");
//从缓存读权限集合
ArrayList<String> permissionLists = (ArrayList) memcachedUtils
.findCache("permissionList");
for (String str : permissionLists) {
permissions.add(dom4jReadXML(str));
}
}
info.setStringPermissions(permissions);
} catch (Exception e) {
logger.debug("权限缓存放入失败");
e.printStackTrace();
}
return info;
}
此处通过自己也有个疑问,shiro的认证和登录是两个独立的过程,但是此处的授权参数是认证方法第一个参数传入对应的属性roleId。(需要深入看看源码)
如果登录接口的缓存放入的权限还未失效,直接比对,否则查库比对。
最后给出数据或者提示。
C.从上面两张图可以看到, shiro 提供了很多拦截器,实现这里可以继承很多不同的拦截器,onAccessDenied就是AccessControlFilter中的。
继承AuthenticatingFilter主要是为了替换底层实现的这一套createToken。
D.最后每次访问返回出错的信息,同一由一个方法输出。这个方法在多个shiro的拦截器中实现,我们替换掉,通过接口转换成json格式输出。
/***
* 认证失败,之后的提示
*
*/
@Override
protected boolean onLoginFailure(AuthenticationToken token,
AuthenticationException e, ServletRequest request,
ServletResponse response) {
HttpServletRequest httpRequest = WebUtils.toHttp(request);
try {
String msg = "客户端[" + InetAddress.getLocalHost().getHostAddress().toString() + "]访问["
+ httpRequest.getRequestURI() + "]认证错误.";
sendChallenge(response, msg, null);
} catch (UnknownHostException e1) {
e1.printStackTrace();
}
return super.onLoginFailure(token, e, request, response);
}
三、总结
1.主要流程也是先认证,后比对权限。认证的时候随机生成的UUID,缓存时间随需要设置。
2.替换内部一套拦截器,按需要的逻辑简化认证授权
3.缓存很重要
四、参考
http://jinnianshilongnian.iteye.com/blog/2041909
相关推荐
在“ssm-shiro权限管理(二)”中,我们将深入探讨如何在Shiro的基础上进一步优化登录流程、实现缓存管理和动态权限分配。Shiro是一个强大且易用的Java安全框架,提供了认证、授权、会话管理和加密等功能,为应用...
在这个“shiro权限管理案例加文档”中,我们很可能会找到关于如何在实际项目中应用Shiro进行权限控制的详细教程和实例。 **一、Shiro基础** Shiro的核心组件包括:Subject(主体)、Realms(域)、Cryptography...
SSM+Shiro权限管理Demo是一个综合性的项目实例,它结合了Spring、Spring MVC(SSM)和Apache Shiro框架来实现一个完善的权限控制体系。这个项目不仅涉及到后端的权限设计,还涵盖了前端页面的展示,使得用户界面与...
Apache Shiro是一个强大且易用的Java安全框架,它提供了认证、授权、加密和会话管理功能,可以非常方便地用于构建和强化应用程序的安全性。本示例将深入讲解Shiro在权限管理中的应用。 首先,我们要理解Shiro的核心...
《SpringBoot-Shiro权限管理系统详解》 在现代的Web开发中,权限管理和用户认证是不可或缺的重要环节。SpringBoot作为一款轻量级的Java框架,以其快速开发、易于配置的特性深受开发者喜爱。Shiro则是Apache组织提供...
【SpringBoot+Shiro权限管理系统脚手架】是基于Spring Boot和Apache Shiro框架构建的高效、便捷的企业级权限管理解决方案。Spring Boot以其简洁的配置和快速开发的特点,已经成为Java Web开发的主流选择,而Shiro则...
SSM-Shiro权限管理是Java Web开发中一种常见的权限控制框架集成方案,它结合了Spring、SpringMVC、MyBatis以及Apache Shiro这四个组件,实现了一个完整的权限管理系统。在本文中,我们将深入探讨如何将这四个组件...
本项目"springboot-shiro-demo_mybatisplus_DEMO_shiro权限管理_"结合了这三个技术,旨在实现一个高效且安全的权限管理系统。下面将详细介绍这些知识点。 **Spring Boot** Spring Boot是基于Spring框架的轻量级开发...
在"Shiro权限管理(一)"这篇博文中,我们可能会探讨Shiro的基础概念和如何在项目中实现基本的权限控制。让我们深入了解一下Shiro的核心组件和使用方法。 1. **身份验证(Authentication)**: Shiro提供了处理...
本文将深入探讨"Springboot+shiro权限管理"的主题,旨在提供最详尽、最清晰的理解路径。 首先,Spring Boot 是一个基于 Spring 框架的轻量级开发工具,它简化了初始化、配置以及运行Spring应用程序的过程。Spring ...
Spring Boot 和 Apache Shiro 的整合是企业级应用中常见的权限认证和安全管理方案。Spring Boot 提供了简化 Java 应用程序开发的框架,而 Shiro 是一个轻量级的安全框架,专注于身份验证、授权、会话管理和加密。...
在本文中,我们将深入探讨Shiro权限管理的相关知识点,以及如何利用它来实现高效的安全控制。 1. **Shiro基础概念** - **身份验证(Authentication)**:确认用户身份的过程,通常涉及用户名和密码的校验。 - **...
在这个"shiro权限管理类项目框架"中,我们将深入探讨 Shiro 如何帮助我们实现权限控制。 Shiro 的核心组件包括: 1. **认证**:这是验证用户身份的过程。在 Shiro 中,我们可以创建一个 `Subject` 对象代表当前...
在这个"shiro权限管理实例"中,我们可以通过学习和实践来深入理解Shiro如何在实际项目中处理用户权限控制。 首先,让我们从身份验证(Authentication)开始。在Shiro中,身份验证是指验证用户提供的身份信息是否...
### SpringMVC+Shiro权限管理系统详解 #### 权限管理概述 权限管理在软件开发中扮演着至关重要的角色,特别是在涉及多用户交互的应用场景下。通过合理的权限控制,可以确保不同用户仅能访问和操作他们被授权的功能...
spring+mybatis+shiro整合。。。简单入门案例,maven项目
移动互联网场景下服务端Shiro权限管理研究 1. 背景介绍 在移动互联网时代,Web系统、App和微信小程序等多种形式的混合应用层出不穷。随之而来的是权限管理的复杂性显著增加。当前的系统权限管理存在授权方式复杂、...
Shiro的授权机制允许基于角色(Role-Based Access Control, RBAC)的权限管理,但在这个Go版本中,我们实现了更细粒度的控制,可以针对单个资源进行授权,超越了传统的RBAC模型。 3. **会话管理(Session ...
Shiro是一个开源的Java...在配置和使用Shiro进行权限管理时,需要对框架有一个全面的理解,包括上述提到的认证、授权、会话管理等核心概念,以及框架的架构细节,这样才能有效地利用Shiro构建出安全稳定的应用程序。
Apache Shiro是一个强大的Java安全框架,它提供了身份验证、授权(权限管理)、会话管理和加密服务。这个示例项目提供了一个完整的Shiro实现,特别强调了权限管理,并且结合了数据库来存储用户和角色信息。从提供的...