1 权限管理

1.1 什么是权限管理?

  • 基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现对用户访问权限的控制,按照安全规则或者安全策略控制用户可以访问而且只能访问自己被授予的权限。
  • 权限管理包括身份认证和授权两部分,简称认证授权。对于需要访问控制的资源,用户首先要经过身份认证,认证通过之后用户具有该资源的访问权限方可访问。

1.2 用户身份认证

1.2.1 概念

  • 身份认证,就是判断一个用户是否为合法用户的处理过程。最常用的简单身份认证方式是系统通过核对用户输入的用户名和口令,看其是否和系统中存储的该用户的用户名和口令一致,来判断用户身份是否正确。
  • 对于采用指纹等系统,则出示指纹。对于硬件key等刷卡系统,则需要刷卡。
  • 系统验证用户身份合法,用户方可访问系统的资源。

1.2.2 用户名密码身份认证流程

1.2.3 关键对象

  • 上面的流程图需要理解以下关键对象。

1.2.3.1 Subject(主体)

  • 访问系统的用户,主体可以是用户、程序等,进行认证的都称为主体。

1.2.3.2 Principal(身份信息)

  • 是主体(Subject)进行身份认证的标识,标识必须具有唯一性,如用户名、手机号码、邮箱地址等等,一个主体可以有多个身份,但是必须只有一个主身份(Primary Principal)。

1.2.3.3 Credential(凭证信息)

  • 主体自己知道的安全信息,如密码、证书等。

1.2.3.4 总结

  • 用户进行身份认证需要提供身份信息和凭证信息。

1.3 授权

1.3.1 概念

  • 授权,即访问控制,控制谁能访问那些系统资源。主体进行身份认证后需要系统分配权限方可访问系统的资源,对于某些资源没有权限是无法访问的。

1.3.2 授权流程

  • 下图中橙色的部分为授权流程。

1.3.3 关键对象

  • 授权可以简单的理解为who对what(which)进行How的操作。

1.3.3.1 Who

  • Who,即主体(Subject),主体在进行身份认证后,才可以访问系统中的资源。

1.3.3.2 What

  • What,即资源(Resource),如系统菜单、页面、按钮、类方法、系统商品信息等等。
  • 资源包括资源类型和资源实例:
    • 比如商品信息为资源类型,类型为t01的商品就是资源实例,编号为001的商品信息也属于资源实例。

1.3.3.3 How

  • How,即权限/许可(Permission),规定了主体对资源的操作许可,权限离开了资源没有意义,如用户查询权限、用户添加权限、某个类方法的调用权限、编号为001的用户的修改权限等,通过权限可以知道主体对那些资源具有那些操作许可。
  • 权限分为粗颗粒度权限和细颗粒度权限:
    • 粗颗粒度权限是指对资源类型的权限。
    • 细颗粒度权限是指对资源实例的权限。  

1.3.3.4 主体、资源、权限关系图

1.3.4 权限模型

  • 对上述中的主体、资源、权限可以通过下面的数据模型来表示。
  • 主体(账号、密码)
  • 资源(资源名称、访问地址)
  • 权限(权限名称、资源id)
  • 角色(角色名称)
  • 角色和权限的关系(角色id、权限id)
  • 主体和角色的关系(主体id、角色id)
  • 如下图:

  • 现在企业开发中通常将资源和权限合并为一张权限表,如下:
  • 资源表(资源名称、访问地址)+权限表(权限名称、资源id)==> 权限(权限名称、资源名称、资源访问地址)

  • 上图常被称为权限管理的通用模型,不过在企业开发中会根据系统自身的特点对上图进行修改,但是用户、角色、权限、用户角色关系、角色权限关系是差不多的。

1.3.5 权限分配

  • 用户需要分配相应的权限才可访问相应的资源。权限是对于资源的操作许可。
  • 通常给用户分配资源权限需要将权限信息持久化,比如存储在关系数据库中。

1.3.6 权限控制

  • 用户拥有了权限即可操作权限范围内的资源,系统不知道主体是否具有访问权限需要对用户进行控制。

1.3.6.1 基于角色的访问控制

  • RBAC基于角色的访问控制(Role Based Access Control)是以角色为中心进行访问控制。
  • 比如:主体的角色为总经理可以查询员工工资信息等,其伪代码如下:
if(user.hasRole("总经理角色id")){
//查询工资
}
  • 缺点:以角色进行访问控制的粒度较粗,如果查询工资的角色变为总经理或部分经理,那么此时就需要修改逻辑为“判断主体的角色是否是总经理或部门经理”,系统的扩展性差。
if(user.hasRole("总经理角色id") || user.hasRole("部门经理角色id")  ){
//查询工资
}

1.3.6.2 基于资源的访问控制

  • RBAC基于资源的访问控制(Resource Based Access Control)是以资源为中心进行访问控制。
  • 比如:主体必须具有查询工资的权限才可以查询员工工资信息等,其伪代码如下:
if(user.hasPermission("查询工资权限标识")){
//查询工资
}
  • 优点:系统设计时定义好查询工资的权限标识,即使查询工资所需要的角色变化为总经理和部门经理也只需要将“查询工资信息权限”添加到“部门经理角色”的权限表中,判断逻辑不用修改,系统可扩展性强。

2 权限管理解决方案

2.1 粗颗粒度和细颗粒度权限管理

2.1.1 什么是粗颗粒度和细颗粒度权限管理?

  • 对资源类型的管理称为粗颗粒度权限管理,即只控制到菜单、按钮、方法等。
  • 比如:超级管理员可以访问用户添加、用户信息等页面,部门管理员可以访问用户信息页面。
  • 对资源实例的管理称为细颗粒度权限管理,即控制到数据级别的权限管理。
  • 比如:部门经理只可以访问本部门的员工信息,用户只能看到自己的菜单、大区经理只能看到本辖区的销售订单等等。

2.1.2 如何实现粗颗粒度和细颗粒度权限管理

  • 对于粗颗粒度的权限管理可以很容易的做到系统架构级别的功能,即系统功能操作使用统一的粗颗粒的权限管理。
  • 对于细颗粒度的谦虚管理不建议做成系统架构级别的功能,因为对数据级别的控制是系统的业务需求,随着业务需求的变更业务功能变化的可能性很大,建议对数据级别的权限控制在业务层个性化开发。比如:部门经理只能查询本部门的员工信息,在service层提供一个部门id的参数的方法,controller层中根据当前用户的信息获取该用户属于那个部门,调用service的时候将部门的id传入进去,就可以实现部门经理只能查询本部门的员工的功能。

2.2 使用权限管理框架

  • 对于权限管理基本上每个系统都有,使用权限管理框架完成权限管理功能的开发可以节省系统开发时间,并且权限管理框架提供了完善的认证和授权功能有利于系统扩展维护,但是学习权限管理框架是需要成本的,所以选择一款简单高效的权限管理框架非常重要。

2.3 基于URL拦截

  • 基于URL拦截是企业中常用的权限管理方式,实现思路是:将系统操作的每个URL配置到权限表中,将权限分配给角色,然后将角色分配给用户,用户访问系统功能的时候通过Filter或拦截器等进行过滤,过滤器或拦截器获取到用户访问的URL,只要访问到的URL是用户分配角色中的URL则放行继续访问。
  • 如下图:

3 Shro介绍

3.1 什么是Shiro?

  • Shiro是Apache旗下的一个开源框架,它将软件系统的安全认证相关的功能抽取出来,实现用户身份认证、权限授权、加密、会话管理等功能,组成了一个通用的安全认证框架。

3.2 为什么要学习Shiro?

  • 既然Shiro将安全认证相关的功能抽取出来组成一个框架,使用shiro就可以非常快速的完成认证、授权等功能的开发,降低系统成本。
  • shiro使用广泛,shiro可以运行在web应用,非web应用,集群分布式应用中越来越多的用户开始使用shiro。
  • Java领域中的Spring Security也是一个开源的权限管理框架,但是Spring Security依赖Spring运行,而Shiro就相对独立,最主要的是因为Shiro使用简单、灵活,所以现在越来越多的用户选择使用Shiro。

3.3 Shiro的架构

3.3.1 Subject

  • Subject即主体,外部应用和Subject进行交互,Subject记录了当前操作的用户,将用户的概念理解为当前操作的主体,可能是一个通过浏览器请求的用户,也可能是一个运行的程序。
  • Subject在Shiro中是一个接口,接口中定义了很多认证授权的方法,外部程序通过Subject进行认证授权,而Subject是通过SecurityManager安全管理器进行认证授权的。

3.3.2 SecurityManager

  • SecurityManager即安全管理器,对全部的Subject进行安全管理,它是Shiro的核心,负责对所有的Subject进行安全管理。通过SecurityManager可以完成Subject的认证、授权等,实质上SecurityManager是通过Authenticator进行认证,通过Authorizer进行授权,通过SessionManager进行会话管理等。
  • SecurityManager是一个接口,继承了Authenticator、Authorizer、SessionManager这三个接口。

3.3.3 Authenticator

  • Authenticator即认证器,对用户身份进行认证,Authenticator是一个接口,Shiro提供ModularRealmAuthenticator实现类,通过ModularRealmAuthenticator基本上可以满足大多数需求,也可以自定义认证器。

3.3.4 Authorizer

  • Authorizer即授权器,用户通过认证器认证通过,在访问功能的时候需要通过授权器判断用户是否有此功能的操作权限。

3.3.5 Realm

  • Realm即领域,相当于DataSource数据源,SecurityManager进行安全认证的时候需要通过Realm获取用户权限数据,比如:如果用户身份数据在数据库,那么Realm就需要从数据库获取用户身份信息。
  • 注意:不要将Realm理解成只是从数据源取数据,在Realm中还有认证授权校验的相关代码。

3.3.6 SessionManager

  • SessionManager即会话管理,Shiro框架定义了一套会话管理,它不依赖web容器的session,所以Shiro可以使用在非web应用上,也可以将分布式应用的会话集中在一点管理,此特性使得它很容易实现单点登录。

3.3.7 SessionDAO

  • SessionDAO即会话DAO,是对Session会话操作的一套接口,比如要将session存储到数据库,可以通过jdbc将会话存储到数据库。

3.3.8 CacheManager

  • CacheManager即缓存管理器,将用户权限数据库存储在缓存中吗,这样可以提高性能。

3.3.9 Cryptography

  • Cryptography即密码管理,Shiro提供了一套加密/解密组件,方便开发。比如提供常用的散列、加密/解密等功能。

3.4 Shiro的jar包

  • 和其他Java开源框架类似,将shiro的jar包加入项目中就可以使用shiro提供的功能了。shiro-core是核心包必须选用,还提供了和web整合的shiro-web,和Spring整合的shiro-spring,和任务调度quartz整合的shiro-quartz等,下边是shiro各个jar包maven坐标。
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-guice</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-cas</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-quartz</artifactId>
<version>1.4.1</version>
</dependency>
  • 也可以通过引入shiro-all引入所有的shirojar包。
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.4.1</version>
<type>pom</type>
</dependency>

4 Shiro的认证

4.1 认证流程

4.2 入门程序

4.2.1 加入shiro的maven坐标

<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.4.1</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>

4.2.2 加入log4j.properties文件

log4j.rootLogger=debug, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n

4.2.3 新建shiro.ini文件

[users]
zhangsan = 123456
lisi = 123456

4.2.4 认证代码

  • 示例:
package com.sunxiaping.shiro;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Test; public class ShiroTest { @Test
public void test() {
//创建SecurityManager工厂对象:加载配置文件,创建工厂对象
Factory<SecurityManager> securityManagerFactory = new IniSecurityManagerFactory("classpath:shiro.ini");
//获取SecurityManager对象
SecurityManager securityManager = securityManagerFactory.getInstance();
//将SecurityManager对象绑定到当前运行环境中,让系统随时随地都可以访问SecurityManager对象
SecurityUtils.setSecurityManager(securityManager);
//获取Subject主体对象
Subject subject = SecurityUtils.getSubject();
//执行登录
try {
subject.login(new UsernamePasswordToken("zhangsan", "123456"));
} catch (UnknownAccountException e) {
System.out.println("用户名不存在");
e.printStackTrace();
} catch (IncorrectCredentialsException e) {
System.out.println("用户名存在,密码不正确");
e.printStackTrace();
}
//判断是否登录成功
boolean authenticated = subject.isAuthenticated(); System.out.println("是否登录:" + authenticated);
//退出
subject.logout(); authenticated = subject.isAuthenticated(); System.out.println("是否登录:" + authenticated); } }

4.2.5 登录登出流程分析

  • ①调用Subject的login()方法进行登录,其会自动委托给SecurityManager的login()方法进行登录。
  • ②SecurityManager通过Authenticator(认证器)认证。
  • ③Authenticator的实现ModularRealmAuthenticator调用realm从ini配置文件获取用户真实账号和密码,这里使用的是IniRealm(shiro自带的,相当于数据源)。
  • ④IniRealm先根据token中的账号去ini中找该账号,如果找不到则ModularRealmAuthenticator返回null,如果找到则匹配密码,匹配密码成功则认证通过。
  • ⑤最后调用Subject的logout()方法进行退出操作。

4.2.6 常见的异常

  • UnknownAccountException:账号不存在异常。
  • IncorrectCredentialsException:密码错误异常。
  • DisabledAccountException:账号被禁用异常。
  • LockedAccountException:账号被锁定异常。
  • ExcessiveAttemptsException:登录失败次数过多。
  • ExpiredCredentialsException:凭证过期。
  • ……

4.3 自定义Realm

  • 上述的程序使用的是Shiro自带的IniRealm。IniRealm从ini配置文件中读取用户信息,大部分情况下需要从系统的数据库中读取用户信息,所以需要自定义Realm。

4.3.1 Shiro提供的Realm

  • 最基本的是Realm接口,CachingRealm负责缓存处理,AuthenticationRealm负责认证,AuthroizingRealm负责授权,通常自定义的Realm继承的是AuthorizingRealm。

4.3.2 自定义Realm

package com.sunxiaping.shiro;

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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection; /**
* 自定义Realm
*/
public class CustomRealm extends AuthorizingRealm { @Override
public String getName() {
return "customRealm";
} @Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
} /**
* 认证
*
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
AuthenticationInfo info = null;
//获取身份信息 zhangsan
Object principal = token.getPrincipal(); //假设从数据库中查询到的zhangsan的密码是123456 String password = "123456";
//一般在实际开发中,SimpleAuthenticationInfo的第一个参数是查询到的用户对象,第二个参数是密码,第三个参数是getName()
info = new SimpleAuthenticationInfo(principal,password,getName()); return info;
}
}

4.3.3 shiro-realm.ini

[main]
# 自定义Realm
customRealm = com.sunxiaping.shiro.CustomRealm
# 将Realm设置到SecurityManager中
securityManager.realms=$customRealm

4.3.4 测试

package com.sunxiaping.shiro;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Test; public class ShiroTest { @Test
public void test() {
//创建SecurityManager工厂对象:加载配置文件,创建工厂对象
Factory<SecurityManager> securityManagerFactory = new IniSecurityManagerFactory("classpath:shiro-realm.ini");
//获取SecurityManager对象
SecurityManager securityManager = securityManagerFactory.getInstance();
//将SecurityManager对象绑定到当前运行环境中,让系统随时随地都可以访问SecurityManager对象
SecurityUtils.setSecurityManager(securityManager);
//获取Subject主体对象
Subject subject = SecurityUtils.getSubject();
//执行登录
try {
subject.login(new UsernamePasswordToken("zhangsan", "123456"));
} catch (UnknownAccountException e) {
System.out.println("用户名不存在");
e.printStackTrace();
} catch (IncorrectCredentialsException e) {
System.out.println("用户名存在,密码不正确");
e.printStackTrace();
}
//判断是否登录成功
boolean authenticated = subject.isAuthenticated(); System.out.println("是否登录:" + authenticated);
//退出
subject.logout(); authenticated = subject.isAuthenticated(); System.out.println("是否登录:" + authenticated); } }

4.4 散列算法

  • 散列算法一般用于生成数据的摘要信息,是一种不可逆的算法,一般适合存储密码之类的数据,常见的散列算法如MD5、SHA等。一般进行散列的时候最好提供一个盐(salt),比如加密密码“admin”,产生的散列值是“21232f297a57a5a743894a0e4a801fc3”,可以到一些md5解密网站很容易的通过散列值得到密码“admin”,即如果直接对密码进行散列相对而言破解很容易,此时我们可以加一些只有系统知道的干扰数据,如用户名和盐(salt),这样散列的对象就是“密码+用户名+盐”,这样生成的散列值相对来说更难破解。

4.4.1 应用示例

  • 示例:
package com.sunxiaping.shiro;

import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.junit.Test; public class SimpleHashTest { @Test
public void test() {
String password = "123456";
Md5Hash md5Hash = new Md5Hash(password);
System.out.println(md5Hash.toString()); //加盐加密
String salt = "sunxiaping";
md5Hash = new Md5Hash(password, salt);
System.out.println(md5Hash.toString()); //加密:md5+盐+散列次数
md5Hash = new Md5Hash(password, salt, 3);
System.out.println(md5Hash.toString()); SimpleHash hash = new SimpleHash("SHA-1", password, salt, 3);
System.out.println(hash.toString()); } }

4.4.2 自定义Realm中使用散列算法

  • 示例:
package com.sunxiaping.shiro;

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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource; /**
* 自定义Realm
*/
public class CustomRealm extends AuthorizingRealm { @Override
public String getName() {
return "customRealm";
} @Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
} /**
* 认证
*
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
AuthenticationInfo info = null;
//获取身份信息 zhangsan
Object principal = token.getPrincipal(); //假设从数据库中查询到的zhangsan的密码是123456
//md5+盐+散列次数(3)
String password = "9666025158cfc769d3d25e40cba317a3";
String salt = "sunxiaping";
//一般在实际开发中,SimpleAuthenticationInfo的第一个参数是查询到的用户对象,第二个参数是密码,第三个参数是getName()
info = new SimpleAuthenticationInfo(principal, password, ByteSource.Util.bytes(salt), getName()); return info;
}
}

4.4.3 Realm的配置

  • shiro-cryptography.ini
[main]
# 定义凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
# 散列算法
credentialsMatcher.hashAlgorithmName=MD5
# 散列次数
credentialsMatcher.hashIterations=3 # 自定义Realm
customRealm = com.sunxiaping.shiro.CustomRealm
# 将凭证匹配器设置到Realm中
customRealm.credentialsMatcher=$credentialsMatcher
# 将Realm设置到SecurityManager中
securityManager.realms=$customRealm

4.4.4 测试

  • 示例:
package com.sunxiaping.shiro;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Test; public class ShiroTest { @Test
public void test() {
//创建SecurityManager工厂对象:加载配置文件,创建工厂对象
Factory<SecurityManager> securityManagerFactory = new IniSecurityManagerFactory("classpath:shiro-cryptography.ini");
//获取SecurityManager对象
SecurityManager securityManager = securityManagerFactory.getInstance();
//将SecurityManager对象绑定到当前运行环境中,让系统随时随地都可以访问SecurityManager对象
SecurityUtils.setSecurityManager(securityManager);
//获取Subject主体对象
Subject subject = SecurityUtils.getSubject();
//执行登录
try {
subject.login(new UsernamePasswordToken("zhangsan", "123456"));
} catch (UnknownAccountException e) {
System.out.println("用户名不存在");
e.printStackTrace();
} catch (IncorrectCredentialsException e) {
System.out.println("用户名存在,密码不正确");
e.printStackTrace();
}
//判断是否登录成功
boolean authenticated = subject.isAuthenticated(); System.out.println("是否登录:" + authenticated);
//退出
subject.logout(); authenticated = subject.isAuthenticated(); System.out.println("是否登录:" + authenticated); } }

Shiro(一)的更多相关文章

  1. shiro权限管理框架与springmvc整合

    shiro是apache下的一个项目,和spring security类似,用于用户权限的管理‘ 但从易用性和学习成本上考虑,shiro更具优势,同时shiro支持和很多接口集成 用户及权限管理是众多 ...

  2. springmvc 多数据源 SSM java redis shiro ehcache 头像裁剪

    获取下载地址   QQ 313596790  A 调用摄像头拍照,自定义裁剪编辑头像 B 集成代码生成器 [正反双向](单表.主表.明细表.树形表,开发利器)+快速构建表单;  技术:31359679 ...

  3. java springMVC SSM 操作日志 4级别联动 文件管理 头像编辑 shiro redis

    A 调用摄像头拍照,自定义裁剪编辑头像 B 集成代码生成器 [正反双向](单表.主表.明细表.树形表,开发利器)+快速构建表单;  技术:313596790freemaker模版技术 ,0个代码不用写 ...

  4. springmvc SSM shiro redis 后台框架 多数据源 代码生成器

    A集成代码生成器 [正反双向(单表.主表.明细表.树形表,开发利器)+快速构建表单 下载地址    ; freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本,处理类 ...

  5. springmvc SSM 多数据源 shiro redis 后台框架 整合

    A集成代码生成器 [正反双向(单表.主表.明细表.树形表,开发利器)+快速构建表单 下载地址    ; freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本,处理类 ...

  6. SpringMVC+Shiro权限管理【转】

    1.权限的简单描述 2.实例表结构及内容及POJO 3.Shiro-pom.xml 4.Shiro-web.xml 5.Shiro-MyShiro-权限认证,登录认证层 6.Shiro-applica ...

  7. shiro的使用2 灵活使用shiro的密码服务模块

    shiro最闪亮的四大特征是认证,授权,加密,会话管理. 上一篇已经演示了如何使用shiro的授权模块,有了shiro这个利器,可以以统一的编码方式对用户的登入,登出,认证进行管理,相当的优雅. 为了 ...

  8. shiro的使用1 简单的认证

    最近在重构,有空学了一个简单的安全框架shiro,资料比较少,在百度和google上能搜到的中文我看过了,剩下的时间有空会研究下官网的文章和查看下源码, 简单的分享一些学习过程: 1,简单的一些概念上 ...

  9. shiro实现session共享

    session共享:在多应用系统中,如果使用了负载均衡,用户的请求会被分发到不同的应用中,A应用中的session数据在B应用中是获取不到的,就会带来共享的问题. 假设:用户第一次访问,连接的A服务器 ...

  10. shiro在springmvc里面的集成使用【转】

    <dependency> <groupId>commons-collections</groupId> <artifactId>commons-coll ...

随机推荐

  1. 关于struts2防止表单重复提交

    struts2防表单重复提交有两种方式. 其一是action的重定向,跳转时设置type为从一个action跳转到另一个action或者另一个页面, 使用户提交后,所停留的位置,不是当前处理数据的Ac ...

  2. Google Home Mini配置失败解决办法

    Google Home Mini配置到最后一步时失败: There was a problem setting up Google Home Mini For help resolving this ...

  3. Metinfo5.1 /about/show.php SQL注入

  4. Element el-table-column组件列宽度设置百分比无效

    问题 使用Element table组件时,给列设置百分比宽度无效(width="30%") 解决 用属性min-width="3"代替属性width=&quo ...

  5. MARKDOWN使用文档

    ISSUE引用 引用当前项目内的ISSUE #1 markdown写法 #1 引用当前命名空间下的其他项目内的ISSUE projectname#1 sofa_ta#1 markdown写法 sofa ...

  6. pandas中的数据结构-DataFrame

    pandas中的数据结构-DataFrame DataFrame是什么? 表格型的数据结构 DataFrame 是一个表格型的数据类型,每列值类型可以不同 DataFrame 既有行索引.也有列索引 ...

  7. POJ2387 Til the Cows Come Home (最短路 dijkstra)

    AC代码 POJ2387 Til the Cows Come Home Bessie is out in the field and wants to get back to the barn to ...

  8. cannot convert from pointer to base class 'QObject' to pointer to derived class 'subClass' via virtual base 'baseClass'

    QT 编译不过的另一个问题: 1. 新建一个console工程 QT -= gui CONFIG += c++ console CONFIG -= app_bundle # The following ...

  9. c++ vector 使用注意事项

    1. 初始化 c++ 11以后新增了大括号{}的初始化方式,需要注意与()的区别,如: std::vector<int> vecTest1(5);         //初始化5个元素,每个 ...

  10. 使用Idea部署SSM项目后,访问路径为url:8080/项目名_war_exploded的解决方案

    在tomcat配置页的Deployment下,修改Application context为/,即可直接使用url:8080访问项目主页.