常用的安全性框架
- apache shhiro
可以应用于任何的应用系统中,不依赖于spring框架。
简单,入门容易。
一般用于传统的SSM的应用比较多。 - springsecurity
是spring框架的其中的模块,必须依赖于spring体系。
功能更强大,较复杂
一般用于springboot+springcloud微服务分布式开发较多
安全性框架的解决目标
- 用户认证 用户登录
- 资源的权限管理 权限(角色)的控制
shiro 框架的架构
说明:
- Security Manager 安全管理器
- Authenticator 认证器 用户的验证(登录)
- Authorizer 授权器 权限管理(控制)
- Session Manager 会话管理器 托管session,进一步对session进行管理
- Session DAO 维护session的数据
- Cache Manager 缓存管理器 用于菜单数据的缓存管理
- Cryptography 提供密码的加密算法 例如, MD5
- Realms "领域"的意思。主要封装验证和授权的业务逻辑的组件。( 系统的realm或 自定义realm)
- Subject 验证的主体, 个人、应用、app
shiro框架的认证流程
shiro的用户认证
入门程序的实现步骤
- 导入 shiro的jar类库
- 添加shiro的配置文件 *.ini
语法:
– [users] 定义用户列表
– [main] ini配置文件对应的容器的“根”,相当于applicationContext.xml中 - 测试代码
@Test //入门认证: 使用默认的realm
public void testLoginAndLogout() {
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-first.ini");
SecurityManager securityManger = factory.getInstance();
//构建securityManger环境
SecurityUtils.setSecurityManager(securityManger);
//获取认证的主体
Subject subject = SecurityUtils.getSubject();
//封装认证的令牌
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "111111");
try {
subject.login(token); // 使用默认的系统的realm做用户认证。
} catch (AuthenticationException e) {
e.printStackTrace();
}
System.out.println("是否认证成功:" + subject.isAuthenticated());
subject.logout();
System.out.println("是否认证成功:" + subject.isAuthenticated());
}
结果:
帐号错误: org.apache.shiro.authc.UnknownAccountException
密码错误:org.apache.shiro.authc.IncorrectCredentialsException
- 自定义realm
package com.gec.shiro.realm;
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;
//需继承AuthorizingRealm
public class CustomRealm extends AuthorizingRealm {
//执行认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//先获取用户的帐号
String username = (String) token.getPrincipal();
//伪代码
// User loginUser = userService.findUserByusername(username);
// if(loginUser == null) {
// return null; //报异常:UnknownAccountException
// }
// String password_db = loginUser.getPassword();
String username_db = "zhangsan";
if(!username.equals(username_db)){
return null;
}
String password_db = "111111";
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password_db, "CustomRealm");
return info;
}
//执行授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
// TODO Auto-generated method stub
return null;
}
}
shiro的权限管理
1.需在配置文件中指定请求 URI 所需的权限标识
<property name="filterChainDefinitions">
<value>
<!-- 所有的静态资源要匿名访问 -->
/bootstrap/**=anon
/css/**=anon
/js/**=anon
/static/**=anon
/images/**=anon
/styles/**=anon
<!-- 授权过滤器 , 建议使用注解授权或在jsp页面使用标签-->
/apply_baoxiao.jsp=perms[baoxiao:apply]
/myBaoxiaoBill=perms[baoxiao:billquery]
/myTaskList=perms[baoxiao:tasklist]
/add_process.jsp=perms[baoxiao:publish]
/processDefinitionList=perms[baoxiao:processlist]
/findUserList=perms[user:query]
/toAddRole=perms[user:create]
/findRoles=perms[baoxiao:rolelist]
/first=user
<!-- 退出系统 -->
/logout=logout
/**=authc
</value>
</property>
2.在自定义 Realm 中给用户授权
//权限授予
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
//从主体中获取用户信息
ActiveUser activeUser = (ActiveUser) principal.getPrimaryPrincipal();
List<SysPermission> permissions = null;
try {
//从数据库中查找用户的权限信息
permissions = sysService.findPermissionListByUserId(activeUser.getUsercode());
} catch (Exception e) {
e.printStackTrace();
}
List<String> percodes = new ArrayList<>();
for (SysPermission sysPermission : permissions) {
//获取权限信息里的权限标识并加入列表
percodes.add(sysPermission.getPercode());
}
//把权限列表授权给用户
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermissions(percodes);
return info;
}
shiro和ssm的整合应用
基础配置如下:
- web.xml
<!-- shiro的filter -->
<!-- shiro过虑器,DelegatingFilterProxy通过代理模式将spring容器中的bean和filter关联起来 -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<!-- 设置true由servlet容器控制filter的生命周期 -->
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
<!-- 设置spring容器filter的bean id,如果不设置则找与filter-name一致的bean -->
<init-param>
<param-name>targetBeanName</param-name>
<param-value>shiroFilter</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- applicationContext.xml spring文件的配置
<!-- 开启aop,对类代理 -->
<aop:config proxy-target-class="true"></aop:config>
<!-- 开启shiro注解支持 -->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager" />
</bean>
<!-- web.xml中shiro的filter对应的bean -->
<!-- Shiro 的Web过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<!-- loginUrl认证提交地址,如果没有认证将会请求此地址进行认证,请求此地址将由formAuthenticationFilter进行表单认证 -->
<property name="loginUrl" value="/login.action" />
<!-- 认证成功统一跳转到first.action,建议不配置,shiro认证成功自动到上一个请求路径 -->
<property name="successUrl" value="/first.action" />
<!-- 通过unauthorizedUrl指定没有权限操作时跳转页面 -->
<property name="unauthorizedUrl" value="/refuse.jsp" />
<!-- 自定义filter配置 -->
<property name="filters">
<map>
<!-- 将自定义 的FormAuthenticationFilter注入shiroFilter中-->
<entry key="authc" value-ref="formAuthenticationFilter" />
</map>
</property>
<!-- 过虑器链定义,从上向下顺序执行,一般将/**放在最下边 -->
<property name="filterChainDefinitions">
<value>
<!-- 所有的静态资源要匿名访问 -->
/js/**=anon
/images/**=anon
/styles/**=anon
/validatecode.jsp=anon
/items/queryItem.action=perms[item:query]
/items/editItems.action=perms[item:update]
<!-- 退出系统 -->
/logout.action=logout
/**=authc
</value>
</property>
</bean>
<!-- securityManager安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="customRealm" />
<property name="cacheManager" ref="cacheManager"/>
</bean>
<!-- realm -->
<bean id="customRealm" class="cn.items.ssm.shiro.CustomRealm">
<property name="credentialsMatcher" ref="credentialsMatcher" />
</bean>
<!-- 凭证匹配器 -->
<bean id="credentialsMatcher"
class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="md5" />
<property name="hashIterations" value="2" />
</bean>
<!-- 自定义form认证过虑器 -->
<!-- 基于Form表单的身份验证过滤器,不配置将也会注册此过虑器,表单中的用户账号、密码及loginurl将采用默认值,建议配置 -->
<bean id="formAuthenticationFilter" class="cn.items.ssm.shiro.CustomFormAuthenticationFilter">
<!-- 表单中账号的input名称 -->
<property name="usernameParam" value="username" />
<!-- 表单中密码的input名称 -->
<property name="passwordParam" value="password" />
</bean>
<!-- 缓存管理器 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:shiro-ehcache.xml"/>
</bean>
用户认证的流程草图: