spring集成shiro

2021年1月16日 15点热度 0条评论 来源: zhangbeizhen18

场景: 
   本例实现用户/口令正常登入,并且实现@RequiresPermissions("sys:user:query")权限验证
1.本例环境
   1>.本例源码下载地址: https://github.com/zhangbeizhen/spring-shiro
   2>.本例环境 shiro + spring + mybatis + eclipse Mars + 基于maven的web项目
   3.1>. spring集成mybatis的源码下载地址: https://github.com/zhangbeizhen/spring-mybatis
   3.2>. spring集成mybatis参考博客地址:  https://blog.csdn.net/zhangbeizhen18/article/details/88575287   

2.本例说明
  本例是在spring集成mybatis的基础上进行集成shiro,本例是本人学习过程中为了适合更好理解shiro改造的domo
  参考了几个开源开源代码,感谢.
3.集成shiro配置文件分成3部分
3.1>在web.xml中配置

<!-- Apache Shiro start-->
<filter>
	<filter-name>shiroFilter</filter-name>
	<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	<init-param>
		<param-name>targetFilterLifecycle</param-name>
		<param-value>true</param-value>
	</init-param>
</filter>
<filter-mapping>
	<filter-name>shiroFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Apache Shiro end-->

3.2>在spring-mvc.xml中配置  

<!-- 支持Shiro对Controller的方法级AOP安全控制 2019-3-21 start -->
<bean
	class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
	depends-on="lifecycleBeanPostProcessor">
	<property name="proxyTargetClass" value="true" />
</bean>
<bean
	class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
	<property name="exceptionMappings">
		<props>
			<prop key="org.apache.shiro.authz.UnauthorizedException">error/403</prop>
			<prop key="java.lang.Throwable">error/500</prop>
		</props>
	</property>
</bean>
<!-- 支持Shiro对Controller的方法级AOP安全控制 end -->

3.3>在spring-context-shiro.xml中配置    

<!-- Shiro权限过滤过滤器定义 -->
<bean name="shiroFilterChainDefinitions" class="java.lang.String">
	<constructor-arg>
		<value>
			/static/** = anon
			/login = authc
			/sys/login/**=anon
			/logout = logout
			/** = authc
		</value>
	</constructor-arg>
</bean>
<!-- 安全认证过滤器 shiroFilter-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
	<property name="securityManager" ref="securityManager" />
	<property name="filterChainDefinitions">
		<ref bean="shiroFilterChainDefinitions"/>
	</property> 
</bean>
<!-- 定义Shiro安全管理配置 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
	<property name="realm" ref="myShiroRealm" />
</bean>
<!-- 注入盐属性2019-3-21 -->
<bean id="myShiroRealm" class="com.zbz.realm.MyShiroRealm">
	<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="3" />
	<!-- 存储散列后的密码是否为16进制 -->
	<!-- <property name="storedCredentialsHexEncoded" value="true" /> -->
</bean>
<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
<!-- AOP式方法级权限检查  -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
	<property name="proxyTargetClass" value="true" />
</bean>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
	<property name="securityManager" ref="securityManager"/>
</bean> 

4.集成shiro的java代码
4.1自定义类继承实现抽象类org.apache.shiro.realm.AuthorizingRealm两个方法
<1>.protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
    此方法在登入时候调用进行登入认证,从数据库中获用户/口令等进行认证,认证成功后即登入了.

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
  logger.info("权限认证开始......");
  UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
  String username = usernamePasswordToken.getUsername();
  UserService userService = SpringUtil.getBean(UserService.class);
  User user = userService.getUser(username);
  if (user == null) {
  	throw new UnknownAccountException("用户名不存在");
  }
  if (!user.getPassword()
  		.equals(userService.passwordEncoder(new String(usernamePasswordToken.getPassword()), user.getSalt()))) {
  	throw new IncorrectCredentialsException("密码错误");
  }
  SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(),
  		ByteSource.Util.bytes(user.getSalt()), getName());
  UserUtil.setUserSession(user);
  logger.info("权限认证结束......");
	return authenticationInfo;
}

<2>.protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals)
    此方法在登入成功后,再次进行访问后调用,进行授权,是否可以访问某个特定方法。

protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
  logger.info("授权开始......");
  SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
  User user = UserUtil.getCurrentUser();
  List<Role> roles = SpringUtil.getBean(RoleDao.class).listByUserId(user.getId());
  Set<String> roleNames = new HashSet<String>();
  if (roles != null && roles.size() > 0) {
  	for (int i = 0; i < roles.size(); i++) {
  		Role role = roles.get(i);
  		if (!StringUtils.isEmpty(role.getName())) {
  			roleNames.add(role.getName());
  		}
  
  	}
  }
  authorizationInfo.setRoles(roleNames);
  List<Permission> permissionList = SpringUtil.getBean(PermissionDao.class).listByUserId(user.getId());
  UserUtil.setPermissionSession(permissionList);
  Set<String> permissions = new HashSet<String>();
  if (permissionList != null && permissionList.size() > 0) {
  	for (int i = 0; i < permissionList.size(); i++) {
  		Permission permission = permissionList.get(i);
  		if (!StringUtils.isEmpty(permission.getPermission())) {
  			permissions.add(permission.getPermission());
  		}
  	}
  }
  authorizationInfo.setStringPermissions(permissions);
  logger.info("授权结束......");
  return authorizationInfo;
}

4.2登入代码,即调用起点

@GetMapping("/sys/login")
public void login(String username, String password) {
  logger.info("登入开始....");
  UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);
  SecurityUtils.getSubject().login(usernamePasswordToken);
  // 设置shiro的session过期时间
  SecurityUtils.getSubject().getSession().setTimeout(30 * 60 * 60 * 1000);
  logger.info("登入完成....");
}

4.3测试权限方法
   本例测试是否有@RequiresPermissions("sys:user:query")权限,
   其中sys:user:query是shiro内部可解析的字符串,同时在数据库权限表中有配置好

@GetMapping("/{id}")
@RequiresPermissions("sys:user:query")
public User user(@PathVariable Long id) {
  logger.info("根据用户id获取用户开始");
  User user = userDao.getById(id);
  logger.info("根据用户id获取用户 结束");
  return user;
}

5.本例共计5张表
  sys_user用户表,sys_role角色表,sys_role_user用户与角色关系表,
  sys_permission权限表,sys_role_permission角色与权限关系表
6.测试url  
    登入: 
    http://127.0.0.1:8080/spring-shiro/sys/login?username=admin&password=admin
    测试权限:
    http://127.0.0.1:8080/spring-shiro/users/1

以上,TKS.

    原文作者:zhangbeizhen18
    原文地址: https://blog.csdn.net/zhangbeizhen18/article/details/88776336
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。