标签:维护 hex primary dac count mes 箭头 es2017 授权
认证流程
Shiro的认证流程可以看作是个“有窗户黑盒”,
整个流程都有框架控制,对外的入口只有subject.login(token);,这代表“黑盒”
流程中的每一个组件,都可以使用Spring IOC容器里的Bean来替换,以实现拓展化、个性化,这代表“有窗户”。
本示例的认证流程可以参考下图:
(黑色区域中的红箭头线只代表受关注组件的流程,而不是直接调用,实际上Shiro每个流程的组件都是互相解耦的)
黑色区域里的两块白色区域,就是两个自定义的类。
关键代码如下:
/** * 认证 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; String username = token.getUsername(); AccountPo po = accountMapper.getByUsername(username); if (po == null) { throw new UnknownAccountException("用户名或密码错误。"); } if (!po.getEnable_flag()) { throw new DisabledAccountException("该用户已被禁用。"); } CredentialsDto credentials = new CredentialsDto(po.getPassword(), po.getSalt()); return new SimpleAuthenticationInfo(username, credentials, getName()); }
/** * 密码匹配 */ @Override public boolean doCredentialsMatch(AuthenticationToken authenticationToken, AuthenticationInfo info) { UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; String password = new String(token.getPassword()); CredentialsDto credentials = (CredentialsDto) info.getCredentials(); String salt = credentials.getSalt(); String passwordMd5 = DigestUtils.md5Hex(password + salt); boolean result = equals(passwordMd5, credentials.getPasswordMd5()); if (!result) { throw new IncorrectCredentialsException("用户名或密码错误。"); } return true; }
认证过滤
直接在spring-shiro.xml的shiroFilter.filterChainDefinitions中定义哪些URL需要认证才能访问并不利于维护,
更合适的方法可能是写一个读取器,告诉filterChainDefinitions哪些URL不需要认证即可,需要认证的写在最后
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <property name="loginUrl" value="/" /> <property name="unauthorizedUrl" value="/html/unauthorized.html" /> <property name="filterChainDefinitions"> <value> #{filterChainDefinitionsLoader.anonUrls()} /**=authc </value> </property> </bean>
/** * Shiro的FilterChainDefinitions配置加载器 * * @author Deolin */ public class FilterChainDefinitionsLoader { @Autowired private UnauthenticationMapper unauthenticationMapper; /** * 从数据库`unauthorization`表中读取所有匿名URL * * @return FilterChainDefinitions内容片段 */ public String anonUrls() { StringBuilder sb = new StringBuilder(400); List<String> urls = authenticationMapper.listUrls(); for (String url : urls) { sb.append(url); sb.append("=anon"); sb.append(CRLF); } return sb.toString(); } }
FilterChainDefinitionsLoader.anonUrls()会在项目启动时调用,读取到所有匿名权限URL,
拼接成字符串,返回给filterChainDefinitions
授权配置
采用基于角色的权限设计,一个权限对应一个URL。一个用户间接地拥有多个权限,间接地能够访问多个权限所一一对应的URL。
这样一来,权限会全部配置在spring-shiro.xml的shiroFilter.filterChainDefinitions中,例如:
/html/students-view.html=perms["students-view"]
/student/add=perms["studentAdd"]
/student/list=perms["studentList"]
红蓝部分都是可自定义的,项目中每个涉及到权限的URL,都应该定义,
并保存到数据库`permission`表的name字段和url字段。
即`permission`是张字典表,项目中有多少个涉及到权限的URL,表中就会有多少字段。
授权配置也需要读取器
<property name="filterChainDefinitions"> <value> #{filterChainDefinitionsLoader.anonUrls()} #{filterChainDefinitionsLoader.permsUrls()} /**=authc </value> </property>
/** * 从数据库`permission`表中读取所有权限 * * @return FilterChainDefinitions内容片段 */ public String permsUrls() { StringBuilder sb = new StringBuilder(400); List<PermissionPo> pos = permissionMapper.list(); for (PermissionPo po : pos) { sb.append(po.getUrl()); sb.append("=perms[\""); sb.append(po.getName()); sb.append("\"]"); sb.append(CRLF); } return sb.toString(); }
授权流程
关键代码如下:
/** * 授权 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = (String) principals.getPrimaryPrincipal(); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); Set<String> roleNames = accountMapper.listRoleNames(username); Set<String> permissionNames = accountMapper.listPermissionNames(username); info.setRoles(roleNames); info.setStringPermissions(permissionNames); return info; }
项目下载
https://github.com/spldeolin/login-demo
标签:维护 hex primary dac count mes 箭头 es2017 授权
原文地址:http://www.cnblogs.com/deolin/p/7637698.html