怎么做公司网站推广/seo优化培训多少钱
根据前面的了解,这次把基于权限的授权通过从数据库中初始化授权实现。
1、分析一下 Shiro 过滤链
<!-- 配置shiro的一些拦截规则,id必须和web.xml中的 shiro 拦截器名一致 --><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"><!-- Shiro的核心安全接口,这个属性是必须的 --> <property name="securityManager" ref="securityManager" /><!-- 身份认证失败,则跳转到登录页面的配置 --> <property name="loginUrl" value="/login" /> <!-- 登录成功后的页面 --><property name="successUrl" value="/admin/index" /> <!-- 权限认证失败,则跳转到指定页面 --> <property name="unauthorizedUrl" value="/unauthorized" /> <!-- 登录后访问没有权限的页面后跳转的页面 --><!-- Shiro连接约束配置,即过滤链的定义 --> <property name="filterChainDefinitions"><value><!-- 注意:规则是有顺序的,从上到下,拦截范围必须是从小到大的url = 拦截规则(anon为匿名,authc为要登录后,才能访问,logout登出过滤) -->/login = anon/logout = logout/admin/userlist = perms[userlist]/admin/addUser = perms[addUser]/admin/** = authc /**= anon </value></property> </bean>
点击 filterChainDefinitions 属性, 进去查看源码
1)可以看到它是 ShiroFilterFactoryBean 的一个属性:
2)经过一系列初始化后,它调用了 setFilterChainDefinitionMap 这个方法,点开这个方法:
3)通过 debug的方式 可以看到在初始化时, filterChainDefinitionMap是一个LinkedHashMap,其内容就是我们在配置文件中配置的内容
所以我们可以配置一个单独的 bean filterChainDefinitionMap 作为ShiroFilterFactoryBean的属性。
然后通过实例工厂的方式来产生Map通过实例工厂注册的Map实例,然后我们需要去新建并配置一个Bean
2、分析后,修改spring.xml
数据库:
将 授权信息 放到 数据库中(事前约束规定,perms使用p: roles 使用 r: )
其他几个表和之前一样,没变化。
用户admin, 只拥有角色 admin 和 user 与访问 /admin/userlist 的权限资源,如果 pid 为3和4,则两者都可访问。
注意:
1)t_permission 的 数据顺序:从上到下,拦截范围必须是从小到大的
2)用户表 model 实现 序列化:
1) 配置bean
<!-- 配置shiro的一些拦截规则,id必须和web.xml中的 shiro 拦截器名一致 --><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"><!-- Shiro的核心安全接口,这个属性是必须的 --> <property name="securityManager" ref="securityManager" /><!-- 身份认证失败,则跳转到登录页面的配置 --> <property name="loginUrl" value="/login" /> <!-- 登录成功后的页面 --><property name="successUrl" value="/admin/index" /> <!-- 权限认证失败,则跳转到指定页面 --> <property name="unauthorizedUrl" value="/unauthorized" /> <!-- 登录后访问没有权限的页面后跳转的页面 --><property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"></property><!-- Shiro连接约束配置,即过滤链的定义 --> <!-- <property name="filterChainDefinitions"><value>注意:规则是有顺序的,从上到下,拦截范围必须是从小到大的url = 拦截规则(anon为匿名,authc为要登录后,才能访问,logout登出过滤)/login = anon/logout = logout/admin/userlist = perms[userlist]/admin/addUser = perms[addUser]/admin/** = authc /**= anon </value></property> --></bean><!-- 通过实例工厂模式的bean配置方式:配置一个bean注入是一个Map实例 --><bean id="filterChainDefinitionMap" factory-bean="filterChainDefinitionMapFactory" factory-method="getFilterChainDefinitionMap"></bean><bean id="filterChainDefinitionMapFactory" class="cn.jq.ssm.service.shiro.FilterChainDefinitionMapFactory"></bean>
2)创建这个bean
import cn.jq.ssm.dao.PermissionMapper;
import cn.jq.ssm.model.Permission;public class FilterChainDefinitionMapFactory {@Autowiredprivate PermissionMapper permissionMapper;public Map<String, String> getFilterChainDefinitionMap(){//从数据库中获取数据List<Permission> permissions = permissionMapper.getAllPermissions();LinkedHashMap<String, String> permsMap = new LinkedHashMap<>();for (Permission permission : permissions) {if(permission.getPname().contains("p:")) {//构造perms[userlist]String perms = permission.getPname().replace("p:", ""); //删除前缀permsMap.put(permission.getUrl(), "perms["+ perms +"]");}else {permsMap.put(permission.getUrl(), permission.getPname());}}return permsMap;}
}
PermissionMapper 方法:
<select id="getAllPermissions" resultType="cn.jq.ssm.model.Permission">selectp.id,p.pname,p.urlfrom t_permission p</select>
3)自定义 ShiroRealm 类, 对于约束 p: 也做相应处理
public class ShiroRealm extends AuthorizingRealm{/** public class ShiroRealm extends AuthenticatingRealm{*/@Autowiredprivate UserMapper userMapper;@Autowiredprivate RoleMapper RoleMapper;@Autowiredprivate PermissionMapper permissionMapper;/*** 在 shiro 中专门做登录验证的方法* @param token* @return* @throws AuthenticationException*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {UsernamePasswordToken token2 = (UsernamePasswordToken) token;String username = token2.getUsername();User user = userMapper.getUserByUsername(username);if(user == null) {throw new UnknownAccountException("用户名或密码有误!");}if(user.getStatus() == 0) {throw new UnknownAccountException("用户名已被禁用,请联系系统管理员!");}/*** principals: 可以使用户名,或d登录用户的对象* hashedCredentials: 从数据库中获取的密码* credentialsSalt:密码加密的盐值* RealmName: 类名(ShiroRealm)*/ByteSource credentialsSalt = ByteSource.Util.bytes("JQSalt");AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPazzword(), credentialsSalt, getName());return info;}/*** 在 shiro 中专门做授权认证的方法*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { //1 从参数 principals 中获取当前登录成功后的用户信息User user = principals.oneByType(User.class);//2 根据第一步中的用户信息,获取角色信息(若用户信息包含角色/权限信息,直接取出,若没有,从数据库中获取)Set<String> roles = RoleMapper.getRolesByUserid(user.getId());// 通过用户关联的role信息,获取角色关联的 permisssion信息Set<String> permissions = permissionMapper.getPermissionsByUserid(user.getId());Set<String> newPermissions = new HashSet<>();for (String permission : permissions) {if(permission.contains("p:")) {//删除约定前缀newPermissions.add(permission.replaceAll("p:", ""));}else {newPermissions.add(permission);}}//3 把获取到的登录用户关联的角色和权限资源信息注入到返回的SimpleAuthorizationInfo对象中SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();info.addRoles(roles);info.addStringPermissions(newPermissions);return info;}}
3、登录访问项目:
结果和分析一致
参考文章: spring工厂方式创建bean实例
end ~