Shiro的介绍

Apache Shiro是一个强大易用的Java安全框架,它提供的主要功能有:

认证 -——用户身份识别,常被称为用户“登录”;

授权—— 访问控制;

密码加密——保护或隐藏数据防止被偷窥;

会话管理——每用户相关的时间敏感的状态。

Shiro的三个核心组件(Subject,SecurityManager 和 Realms)介绍

Subject:“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。但考虑到大多数目的和用途,你可以把它认为是Shiro的“用户”概念。 Subject代表的是当前用户的安全操作。

SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。

Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。(当配置Shiro时,你至少要指定一个Realm,用于认证和(或)授权,至少需要一个。 Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。)

下图为Shiro功能模块结构:

这些模块各有作用:

Authentication:身份认证/登录,验证用户是不是拥有相应的身份;

Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;

Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;

Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;

Web Support:Web支持,可以非常容易的集成到Web环境;

Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;

Concurrency:shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;

Testing:提供测试支持;

Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;

Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。

Shiro依赖包

maven环境下,pom.xml中依赖包配置:

<dependency>  <groupId>org.apache.shiro</groupId>  <artifactId>shiro-core</artifactId>  <version>1.2.3</version>
</dependency>
<dependency>  <groupId>org.apache.shiro</groupId>  <artifactId>shiro-web</artifactId>  <version>1.2.3</version>
</dependency>
<dependency>  <groupId>org.apache.shiro</groupId>  <artifactId>shiro-ehcache</artifactId>  <version>1.2.3</version>
</dependency>
<dependency>  <groupId>org.apache.shiro</groupId>  <artifactId>shiro-spring</artifactId>  <version>1.2.3</version>
</dependency>

web工程中引入Shiro框架,首先要在web.xml中配置:

<!-- Apache Shiro --><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:application.xml,classpath:shiro/spring-shiro.xml</param-value></context-param><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>/*</url-pattern>
</filter-mapping>

web程序启动时,首先会加载spring-shiro.xml配置文件,然后执行web中的过滤器,实现安全登录。

配置Realm,进行验证及授权

定义该一个安全认证的实现类,需要继承AuthorizingRealm并实现登录验证和赋予角色权限的两个方法

即:

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationTokenauthcToken);--------登录认证时使用

protected AuthorizationInfogetAuthorizationInfo(PrincipalCollection principals);---------用户授权时使用

还可以自定义一些其他业务中使用到的方法,如下:

@SuppressWarnings("restriction")
@Service
//@DependsOn({"userDao","roleDao","menuDao"})
public class SystemAuthorizingRealm extends AuthorizingRealm {private Logger logger = LoggerFactory.getLogger(getClass());private SystemService systemService;public SystemAuthorizingRealm() {this.setCachingEnabled(false);}/*** 认证回调函数, 登录时调用*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) {UsernamePasswordToken token = (UsernamePasswordToken) authcToken;int activeSessionSize = getSystemService().getSessionDao().getActiveSessions(false).size();if (logger.isDebugEnabled()){logger.debug("login submit, active session size: {}, username: {}", activeSessionSize, token.getUsername());}// 校验登录验证码if (LoginController.isValidateCodeLogin(token.getUsername(), false, false)){Session session = UserUtils.getSession();String code = (String)session.getAttribute(ValidateCodeServlet.VALIDATE_CODE);if (token.getCaptcha() == null || !token.getCaptcha().toUpperCase().equals(code)){throw new AuthenticationException("msg:验证码错误, 请重试.");}}// 校验用户名密码User user = getSystemService().getUserByLoginName(token.getUsername());if (user != null) {if (Global.NO.equals(user.getLoginFlag())){throw new AuthenticationException("msg:该已帐号禁止登录.");}byte[] salt = Encodes.decodeHex(user.getPassword().substring(0,16));return new SimpleAuthenticationInfo(new Principal(user, token.isMobileLogin()), user.getPassword().substring(16), ByteSource.Util.bytes(salt), getName());} else {return null;}}/*** 获取权限授权信息,如果缓存中存在,则直接从缓存中获取,否则就重新获取, 登录成功后调用*/protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {if (principals == null) {return null;}AuthorizationInfo info = null;info = (AuthorizationInfo)UserUtils.getCache(UserUtils.CACHE_AUTH_INFO);if (info == null) {info = doGetAuthorizationInfo(principals);if (info != null) {UserUtils.putCache(UserUtils.CACHE_AUTH_INFO, info);}}return info;}/*** 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {Principal principal = (Principal) getAvailablePrincipal(principals);// 获取当前已登录的用户if (!Global.TRUE.equals(Global.getConfig("user.multiAccountLogin"))){Collection<Session> sessions = getSystemService().getSessionDao().getActiveSessions(true, principal, UserUtils.getSession());if (sessions.size() > 0){// 如果是登录进来的,则踢出已在线用户if (UserUtils.getSubject().isAuthenticated()){for (Session session : sessions){getSystemService().getSessionDao().delete(session);}}// 记住我进来的,并且当前用户已登录,则退出当前用户提示信息。else{UserUtils.getSubject().logout();throw new AuthenticationException("msg:账号已在其它地方登录,请重新登录。");}}}User user = getSystemService().getUserByLoginName(principal.getLoginName());if (user != null) {SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();List<Menu> list = UserUtils.getMenuList();for (Menu menu : list){if (StringUtils.isNotBlank(menu.getPermission())){// 添加基于Permission的权限信息for (String permission : StringUtils.split(menu.getPermission(),",")){info.addStringPermission(permission);}}}// 添加用户权限info.addStringPermission("user");// 添加用户角色信息for (Role role : user.getRoleList()){info.addRole(role.getEnname());}// 更新登录IP和时间getSystemService().updateUserLoginInfo(user);// 记录登录日志LogUtils.saveLog(Servlets.getRequest(), "系统登录");return info;} else {return null;}}@Overrideprotected void checkPermission(Permission permission, AuthorizationInfo info) {authorizationValidate(permission);super.checkPermission(permission, info);}@Overrideprotected boolean[] isPermitted(List<Permission> permissions, AuthorizationInfo info) {if (permissions != null && !permissions.isEmpty()) {for (Permission permission : permissions) {authorizationValidate(permission);}}return super.isPermitted(permissions, info);}@Overridepublic boolean isPermitted(PrincipalCollection principals, Permission permission) {authorizationValidate(permission);return super.isPermitted(principals, permission);}@Overrideprotected boolean isPermittedAll(Collection<Permission> permissions, AuthorizationInfo info) {if (permissions != null && !permissions.isEmpty()) {for (Permission permission : permissions) {authorizationValidate(permission);}}return super.isPermittedAll(permissions, info);}/*** 授权验证方法* @param permission*/private void authorizationValidate(Permission permission){// 模块授权预留接口}/*** 设定密码校验的Hash算法与迭代次数*/@PostConstructpublic void initCredentialsMatcher() {HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(SystemService.HASH_ALGORITHM);matcher.setHashIterations(SystemService.HASH_INTERATIONS);setCredentialsMatcher(matcher);}/*** 获取系统业务对象*/public SystemService getSystemService() {if (systemService == null){systemService = SpringContextHolder.getBean(SystemService.class);}return systemService;}/*** 授权用户信息*/public static class Principal implements Serializable {private static final long serialVersionUID = 1L;private String id; // 编号private String loginName; // 登录名private String name; // 姓名private boolean mobileLogin; // 是否手机登录//     private Map<String, Object> cacheMap;public Principal(User user, boolean mobileLogin) {this.id = user.getId();this.loginName = user.getLoginName();this.name = user.getName();this.mobileLogin = mobileLogin;}public String getId() {return id;}public String getLoginName() {return loginName;}public String getName() {return name;}public boolean isMobileLogin() {return mobileLogin;}/*** 获取SESSIONID*/public String getSessionid() {try{return (String) UserUtils.getSession().getId();}catch (Exception e) {return "";}}@Overridepublic String toString() {return id;}}
}

Shiro配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsdhttp://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.1.xsd"default-lazy-init="true"><description>Shiro Configuration</description><!-- 加载配置属性文件 --><context:property-placeholder ignore-unresolvable="true" location="classpath:jeesite.properties" /><!-- Shiro权限过滤过滤器定义 --><bean name="shiroFilterChainDefinitions" class="java.lang.String"><constructor-arg><value>/static/** = anon/userfiles/** = anon${adminPath}/cas = cas${adminPath}/login = authc${adminPath}/logout = logout${adminPath}/** = user/act/editor/** = user/ReportServer/** = user</value></constructor-arg></bean><!-- 安全认证过滤器 --><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"><property name="securityManager" ref="securityManager" /><property name="loginUrl" value="${adminPath}/login" /><property name="successUrl" value="${adminPath}?login" /><property name="filters"><map><entry key="cas" value-ref="casFilter"/><entry key="authc" value-ref="formAuthenticationFilter"/></map></property><property name="filterChainDefinitions"><ref bean="shiroFilterChainDefinitions"/></property></bean><!-- CAS认证过滤器 -->  <bean id="casFilter" class="org.apache.shiro.cas.CasFilter">  <property name="failureUrl" value="${adminPath}/login"/></bean><!-- 定义Shiro安全管理配置 --><bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><property name="realm" ref="systemAuthorizingRealm" /><property name="sessionManager" ref="sessionManager" /><property name="cacheManager" ref="shiroCacheManager" /></bean><!-- 自定义会话管理配置 --><bean id="sessionManager" class="com.thinkgem.jeesite.common.security.shiro.session.SessionManager"> <property name="sessionDAO" ref="sessionDAO"/><!-- 会话超时时间,单位:毫秒  --><property name="globalSessionTimeout" value="${session.sessionTimeout}"/><!-- 定时清理失效会话, 清理用户直接关闭浏览器造成的孤立会话   --><property name="sessionValidationInterval" value="${session.sessionTimeoutClean}"/>
<!--         <property name="sessionValidationSchedulerEnabled" value="false"/> --><property name="sessionValidationSchedulerEnabled" value="true"/><property name="sessionIdCookie" ref="sessionIdCookie"/><property name="sessionIdCookieEnabled" value="true"/></bean><!-- 指定本系统SESSIONID, 默认为: JSESSIONID 问题: 与SERVLET容器名冲突, 如JETTY, TOMCAT 等默认JSESSIONID,当跳出SHIRO SERVLET时如ERROR-PAGE容器会为JSESSIONID重新分配值导致登录会话丢失! --><bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie"><constructor-arg name="name" value="jeesite.session.id"/></bean><!-- 自定义Session存储容器 --><bean id="sessionDAO" class="com.thinkgem.jeesite.common.security.shiro.session.CacheSessionDAO"><property name="sessionIdGenerator" ref="idGen" /><property name="activeSessionsCacheName" value="activeSessionsCache" /><property name="cacheManager" ref="shiroCacheManager" /></bean><!-- 自定义系统缓存管理器--><bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"><property name="cacheManager" ref="cacheManager"/></bean><!-- 保证实现了Shiro内部lifecycle函数的bean执行 --><bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/><!-- AOP式方法级权限检查  --><bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"><property name="proxyTargetClass" value="true" /></bean><bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"><property name="securityManager" ref="securityManager"/></bean></beans>

这里做一下说明,Shiro默认到的权限验证类别:

anon --org.apache.shiro.web.filter.authc.AnonymousFilter

authc -- org.apache.shiro.web.filter.authc.FormAuthenticationFilter

authcBasic --org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter

perms --org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter

port --org.apache.shiro.web.filter.authz.PortFilter

rest --org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter

roles --org.apache.shiro.web.filter.authz.RolesAuthorizationFilter

ssl --org.apache.shiro.web.filter.authz.SslFilter

user --org.apache.shiro.web.filter.authc.UserFilter

logout --org.apache.shiro.web.filter.authc.LogoutFilter

 解释:

anon---例子/admins/**=anon没有参数,表示可以匿名使用。

authc---例子/admins/user/**=authc表示需要认证(登录)才能使用,没有参数

roles---例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。

perms---例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。

rest---例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method],其中method为post,get,delete等。

port---例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString是你访问的url里的?后面的参数。

authcBasic---例如/admins/user/**=authcBasic没有参数表示httpBasic认证

ssl---例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https

user---例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查

注意:

Shiro.xml加载配置是从上而下的,也就是向上面的配置,如/** = anon  ,如果把这个配置在第一行,那么下面的配置都没用。因为是从上往下去匹配,只要匹配中了,就不匹配了所以必须要有序。

spring整合应用安全框架Shiro相关推荐

  1. Spring整合定时任务调度框架Quartz实

    Spring整合定时任务调度框架Quartz实战 定时的任务处理在程序开发中应用的相当普遍,之前一直使用JDK的Timer类库来做任务调度功能不是很方便,因为它不能像cron服务那样可以指定具体年.月 ...

  2. spring整合各种RPC框架(netty、dubbo、dubbox、gRPC、Motan)-续(Motan)

    继上文 :spring整合各种RPC框架(netty.dubbo.dubbox.gRPC.Motan)-续(gRPC) Motan相关介绍? Motan是新浪微博开源的一套基于java开发的RPC框架 ...

  3. 一个jsp能取到父类jsp的值吗_「Javaweb」ssm整合权限控制框架shiro,你知道怎么做吗?...

    为美好而努力--羊羽科技说. 最近在开发自己的网站,需要权限控制功能,在网上找了一下,找到了我接下来要介绍的shiro框架. shiro框架是Apache公司维护的开源产品之一,其官网对其的简介是这样 ...

  4. 原创:Spring整合junit测试框架(简易教程 基于myeclipse,不需要麻烦的导包)

    我用的是myeclipse 10,之前一直想要用junit来测试含有spring注解或动态注入的类方法,可是由于在网上找的相关的jar文件进行测试,老是报这样那样的错误,今天无意中发现myeclips ...

  5. 【struts2+spring+hibernate】ssh框架整合开发

    SSH框架整合 1 Struts2+Spring+Hibernate导包 Struts2导入jar包: * struts2/apps/struts2-blank.war/WEB-INF/lib/*.j ...

  6. spring整合quartz框架定时任务实战

    Spring整合定时任务调度框架Quartz实战 2014-09-12 11:51 9707人阅读 评论(6) 收藏 举报  分类: [综合问题](74)  版权声明:本文为博主原创文章,未经博主允许 ...

  7. IDEA优雅整合Maven+SSM框架(详细思路+附带源码)

    前言: 网上很多整合SSM博客文章并不能让初探ssm的同学思路完全的清晰,可以试着关掉整合教程,摇两下头骨,哈一大口气,就在万事具备的时候,开整,这个时候你可能思路全无 ~中招了咩~ ,还有一些同学依 ...

  8. shiro和Spring整合使用注解时没有执行realm的doGetAuthorizationInfo回调方法的解决

    shiro和Spring整合使用注解时没有执行realm的doGetAuthorizationInfo回调方法的解决 from :http://blog.csdn.net/babys/article/ ...

  9. 在Spring MVC中使用Apache Shiro安全框架

    我们在这里将对一个集成了Spring MVC+Hibernate+Apache Shiro的项目进行了一个简单说明.这个项目将展示如何在Spring MVC 中使用Apache Shiro来构建我们的 ...

最新文章

  1. python录制视频和声音_python录制系统声音
  2. 职场10不要【来自网络】
  3. 零基础 ABAP 学习教程系列文章的目录
  4. 编写linux驱动程序步骤
  5. Python 反爬篇之 ID 混淆
  6. [链接].VGA信号时序
  7. 2021年CBA总决赛第三场预测
  8. 学英语专业后悔了_上大学一定不要读英语专业?当年志愿填报我选了英语专业...
  9. Dockerfile 中的 CMD 与 ENTRYPOINT
  10. 明月浩空播放器php源码,明月浩空音乐播放器
  11. 泛型:泛型类与泛型方法
  12. PTA L2-048 寻宝图 (25 分)
  13. 1024程序员节 技术对抗赛 算法与安全答题 标准答案
  14. RFID门禁系统快速识别车辆管理
  15. 未来计算机语言的发展趋势,编程语言的发展趋势及未来方向 I
  16. 天气预报API接口整理
  17. 修改默认文件夹的图标(使用注册表)
  18. 关于亚马逊云的负载均衡器(AWS-LD)的相关问题记录
  19. 章文嵩:服务器定制与绿色计算
  20. Android安卓开发源码(联系人页)

热门文章

  1. Bose 700无线消噪耳机评测:让用户不受打扰是它最大的温柔
  2. 《哪吒》票房破31亿元 超越《药神》升至中国票房榜第七
  3. 沃尔玛牵手Gatik推行自动驾驶试点项目 为客户配送订单
  4. 金立旗下18辆车产被司法拍卖 成交额近500万元
  5. 苹果iPhone XI奋起直追?直接升级四摄镜头
  6. 没有黑色版本?AirPods 2广告泄露:外型无变化
  7. 情人节福利,用JAVA做个QQ机器人,帮我提醒女神按时喝水和陪她聊天~(开源)
  8. java类和对象:封装、继承和多态
  9. 线性表:5.约瑟夫环,循环链表及其C语言实现
  10. python unittest教程_Python Unittest原理及基本使用方法