一、权限管理
- Apache Shiro
Apache Shiro 是一个强大且易用的 Java 安全框架,执行身份验证、授权、密码和会话管理。使
用 Shiro 的易于理解的 API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最
大的网络和企业应用程序。
- Apache Shiro
- Spring Security
Spring Security 以前叫做 acegi,是后来才成为 Spring 的一个子项目,也是目前最为流行的一个
安全权限管理框架,它与 Spring 紧密结合在一起。
- Spring Security
- 使用:shiro轻量级,易使用,独立运行,security 对 spring 结合较好,如果项目用的 springmvc ,使用起来很方便
二、 shiro
Shiro 是 Java 的一个安全框,Shiro 可以帮助我们完成:认证、授权、加密、会话管理、与 Web 集成、缓存等架
- Subject(用户): 访问系统的用户,主体可以是用户、程序等,进行认证的都称为主体;
Subject 一词是一个专业术语,其基本意思是“当前的操作用户”。它是一个抽象的概念,可以是
人,也可以是第三方进程或其他类似事物,如爬虫,机器人等。 在程序任意位置:Subject
currentUser = SecurityUtils.getSubject(); 类似 Employee user = UserContext.getUser()
一旦获得 Subject,你就可以立即获得你希望用 Shiro 为当前用户做的 90%的事情,如登录、
登出、访问会话、执行授权检查等- SecurityManager(安全管理器) 安全管理器,它是 shiro 功能实现的核心,负责与后边介绍的
其他组件(认证器/授权器/缓存控制器)进行交互,实现 subject 委托的各种功能。有点类似于
SpringMVC 中的 DispatcherServlet 前端控制器。- Realms(数据源) Realm 充当了 Shiro 与应用安全数据间的“桥梁”或者“连接器”。;可以把
Realm 看成 DataSource,即安全数据源。执行认证(登录)和授权(访问控制)时,Shiro 会
从应用配置的 Realm 中查找相关的比对数据。以确认用户是否合法,操作是否合理- Authenticator Authenticator 用于认证,协调一个或者多个 Realm,从 Realm 指定的数据源取得
数据之后进行执行具体的认证。- Authorizer Authorizer 用户访问控制授权,决定用户是否拥有执行指定操作的权限。
- SessionManager Shiro 与生俱来就支持会话管理,这在安全类框架中都是独一无二的功能。即
便不存在 web 容器环境,shiro 都可以使用自己的会话管理机制,提供相同的会话 API。- CacheManager 缓存组件,用于缓存认证信息等。
- Cryptography Shiro 提供了一个加解密的命令行工具 jar 包,需要单独下载使用。
Shiro 架构的核心(Subject,SecurityManager,Realms)
三、shiro的使用
subject 主体 ,当前登录用户 (里面有个状态可以区分是否有登录)
securityManager 安全管理器,管理很多组件,分发调度
realm数据源 , 提供数据给shiro进行逻辑处理
- 常见认证登录失败存在错误:
- 账号错误
org.apache.shiro.authc.UnknownAccountException - 密码错误
org.apache.shiro.authc.IncorrectCredentialsException
四、CRM 中集成 Shiro 认证
添加依赖
<shiro.version>1.5.2</shiro.version>
<!--shiro 核心 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<!--shiro 的 Web 模块 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>${shiro.version}</version>
</dependency>
<!--shiro 和 Spring 集成 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<!--shiro 底层使用的 ehcache 缓存 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
<!--shiro 依赖的日志包 -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!--shiro 依赖的工具包 -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<!--Freemarker 的 shiro 标签库 -->
<dependency>
<groupId>net.mingsoft</groupId>
<artifactId>shiro-freemarker-tags</artifactId>
<version>1.0.1</version>
<exclusions>
<exclusion>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
</exclusion>
</exclusions>
</dependency>
配置shiro代理过滤器
shiro 过虑器,DelegatingFilterProx 会从 spring 容器中找 shiroFilter
web.xml
<!-- spring 提供的代理过滤器,当代理过滤器接收到请求后,会在spring容器中找真正的bean<filter-name>来执行 -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<servlet-name>springDispatcherServlet</servlet-name>
<!-- 使用/*可以拦截所有资源,包括静态资源,可以更好的对静态资源进行权限判断 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
配置数据源(realm)
CrmRealm.java
@Component
public class CrmRealm extends AuthorizingRealm {
@Autowired
private EmployeeMapper employeeMapper;
@Override
@Autowired
// 注入凭证匹配器
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
super.setCredentialsMatcher(credentialsMatcher);
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 通过tokan获取用户名(用户登录的时候填的)
Object username = token.getPrincipal();
// 判断是否存在数据库
Employee employee = employeeMapper.selectByName((String) username);
// 判断是否账号被禁用
if (!employee.isStatus()){
throw new DisabledAccountException();
}
if (employee!=null) {
// 一个项目可以有多个realm, 查出来的数据从哪个realm中查出来的 ,需要标记一下
// 身份信息,凭证信息(正确),盐,当前realm的名字
return new SimpleAuthenticationInfo(employee,employee.getPassword(),
ByteSource.Util.bytes(username),"CrmRealm");
}
// 返回值就是查询出来的数据,如果查到这个账号,就应该返回该账号的正确的数据,如果查询不到返回null
return null;
}
/**
* 授权,代码中需要 判断授权 hasxxx的时候才会执行
*
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
}
配置真正的shiro过滤器(在 mvc.xml 中引入)
shiro.xml
<!-- shiro过滤器 spring管理 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!--引用指定的安全管理器-->
<property name="securityManager" ref="securityManager"/>
<!-- shiro默认的登录地址是login.jsp,现在指定为自己的登录页面地址 -->
<property name="loginUrl" value="/login.html"/>
<!-- 路径对应的规则 -->
<property name="filterChainDefinitions">
<!-- 有前后顺序,先配置先生效 -->
<value>
/login.do=anon
/css/**=anon
/js/**=anon
/logout.do=logout
/**=authc
</value>
</property>
</bean>
<!-- 安全管理器 分发调度-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- 配置数据源 -->
<property name="realm" ref="crmRealm"/>
<!-- 注册缓存管理器 -->
<property name="cacheManager" ref="cacheManager"/>
</bean>
登录功能
//封装令牌
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
// 利用shiro的api来进行登录
SecurityUtils.getSubject().login(token);
注销功能
shiro.xml
直接配置 /logout.do = logout 交给shiro提供的注销过滤器去处理
密码加密
密码加密加盐.png- 指定加密使用的盐为当前用户的用户名
// 身份信息,凭证信息(正确),盐,当前realm的名字
return new SimpleAuthenticationInfo(employee,employee.getPassword(), ByteSource.Util.bytes(username),"CrmRealm");
- 在添加员工时,先加密,再保存
(密码+用户名)的加盐方式
// 密码进行加密(盐)
Md5Hash md5HashPwd = new Md5Hash(employee.getPassword(), employee.getName());
employee.setPassword(md5HashPwd.toString());
- shiro.xml配置凭证匹配器,配置算法,注入realm,在realm中传入盐的数据
shiro.xml
<!-- 凭证匹配器 -->
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!-- 加密的算法 -->
<property name="hashAlgorithmName" value="md5"/>
<!--<property name="hashIterations" value="50"/>-->
</bean>
网友评论