shiro架构图
subject | 主体,可以是用户也可以是程序,主体要访问系统,系统需要对主体进行认证、授权。 |
securityManager | 安全管理器,主体进行认证和授权都 是通过securityManager进行。它包含下面的认证器和授权器。 |
authorizer | 授权器,主体进行授权最终通过authorizer进行的。 |
authenticator | 认证器,主体进行认证最终通过authenticator进行的。 |
sessionManager | web应用中一般是用web容器对session进行管理,shiro也提供一套session管理的方式。可以实现单点登录。 |
SessionDao | 通过SessionDao管理session数据,针对个性化的session数据存储需要使用sessionDao。 |
cache Manager | 缓存管理器,主要对session和授权数据进行缓存,比如将授权数据通过cacheManager进行缓存管理,和ehcache整合对缓存数据进行管理。 |
realm | 域,领域,相当于数据源,通过realm存取认证、授权相关数据。(它的主要目的是与数据库打交道,查询数据库中的认证的信息(比如用户名和密码),查询授权的信息(比如权限的code等,所以这里可以理解为调用数据库查询一系列的信息,一般情况下在项目中采用自定义的realm,因为不同的业务需求不一样)) |
cryptography | 密码管理,提供了一套加密/解密的组件,方便开发。比如提供常用的散列、加/解密等功能。
比如 md5散列算法。 |
shiro的使用
1、realm类的编写
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.jt.sys.service.realms; import com.alibaba.druid.util.StringUtils; public class ShiroUserRealm extends AuthorizingRealm { @Autowired private SysUserDao sysUserDao; /** * 获取授权信息 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { System.out.println("--doGetAuthorizationInfo(PrincipalCollection principals) "); //1、获取用户信息 SysUser sysUser = sysUserDao.findUserByUsername(principals.toString()); System.out.println(sysUser.toString()); //2、获取用户权限 List<String> list = sysUserDao.findUserPermissions(sysUser.getId()); if(list==null)return null; Set<String> permissions = new HashSet<String>(); for(String permission : list){ if(!StringUtils.isEmpty(permission)){ permissions.add(permission); } } //3、返回封装的用户权限信息 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.setStringPermissions(permissions); //4、将授权信息返回给授权管理器 return info; } /** * 获取认证信息 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken userToken = (UsernamePasswordToken)token; String username = userToken.getUsername(); SysUser user = sysUserDao.findUserByUsername(username); if(user.getValid()==null || !"1".equals(user.getValid())){ return null; } ByteSource salt = ByteSource.Util.bytes(user.getSalt()); AuthenticationInfo ai = new SimpleAuthenticationInfo(username,user.getPassword(),salt,getName()); //将认证信息返回给认证管理器 return ai; } }
2、使用md5 对密码进行加密
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//使用md5对密码进行加密 String salt = UUID.randomUUID().toString(); String password = sysUser.getPassword(); SimpleHash sHash = new SimpleHash("MD5",password,salt); String newPwd = sHash.toString(); sysUser.setSalt(salt); sysUser.setPassword(newPwd);
3、登陆业务的处理
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public void login(String username, String password) { //0、参数合法性验证 if(username==null || "".equals(username)) throw new ServiceException("用户名不能为空"); if(password==null || "".equals(password)) throw new ServiceException("密码不能为空"); //1、获取Subject(主体)对象 Subject subject = SecurityUtils.getSubject(); //2、封装用户名和密码 UsernamePasswordToken token = new UsernamePasswordToken(username,password); //3、执行身份验证 try { subject.login(token); }catch (UnknownAccountException e) { throw new ServiceException("认证失败:当前用户已被禁用!"); } catch (AuthenticationException e) { e.printStackTrace(); throw new ServiceException("认证失败:用户名或密码不正确!"); } //4、记录用户的session SecurityUtils.getSubject().getSession().setAttribute("user", username); }
4、spring整合shiro配置
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?xml version="1.0" encoding="UTF-8"?> <beans default-lazy-init="true" xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <!-- 整合shiro配置 --> <!-- 配置shiro安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="rememberMeManager" ref="remeberManager" /> <property name="cacheManager" ref="cacheManager"/> <property name="realm" ref="shiroUserRealm" /> </bean> <!-- spring整合配置ehcache缓存 --> <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/> </bean> <!-- 配置 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- shiro的核心安全接口 --> <property name="securityManager" ref="securityManager" /> <!-- 要求登录时的连接 --> <property name="loginUrl" value="/loginUI.do"></property> <!-- 登录成功后要跳转的连接(此处已经在登录中处理了) --> <!-- <property name="successUrl" value="/index.jsp"></property> --> <!-- 访问未对其授权的资源时,要跳转的连接 <property name="unauthorizedUrl" value="/default.html"></property> --> <!-- shiro连接约束配置 --> <property name="filterChainDefinitions"> <value> <!-- 对静态资源设置允许匿名访问 --> /bower_components/** = anon /build/** = anon /dist/** = anon /plugins/** = anon /doLogin.do = anon <!-- 退出 --> /logout.do = logout <!-- 会调用Subject的logout方法,此方法会将session清空 --> <!-- 剩余其他路径,必须认证通过才可以访问 --> /** = authc </value> </property> </bean> <!-- 自定义Realm --> <bean id="shiroUserRealm" class="com.jt.sys.service.realms.ShiroUserRealm"> <!-- 配置凭证算法匹配器 --> <property name="credentialsMatcher"> <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> <property name="hashAlgorithmName" value="MD5" /> <!-- <property name="hashIterations" value="1024"/> --> </bean> </property> </bean> <!--Shiro生命周期处理器 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> <!--启用shiro注解权限检查 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor" /> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager" /> </bean> <!-- 记住我配置 --> <bean id="remeberManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager"> <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}" /> <property name="cookie" ref="remeberMeCookie" /> </bean> <!-- 记住我cookie --> <bean id="remeberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="remeberMe" /> <property name="path" value="/" /> <property name="httpOnly" value="true"/> <property name="maxAge" value="604800" /> </bean> </beans>
权限控制方式
可在方法前加注解:
@RequiresPermissions("sys:role:roleUI")
@RequiresPermissions(value = {"sys:role:update","sys:role:add"},logical=Logical.OR)
@RequiresPermissions(value = {"sys:role:update","sys:role:add"},logical=Logical.AND)