SpringBoot 集成Shrio 用户权限管理分析

你猜 阅读:282 2021-03-31 18:15:16 评论:0

1、boot-shrio 建库脚本:

DROP TABLE IF EXISTS `u_permission`; 
CREATE TABLE IF NOT EXISTS `u_permission` ( 
  `id` bigint(20) NOT NULL AUTO_INCREMENT, 
  `url` varchar(256) DEFAULT NULL COMMENT 'url地址', 
  `name` varchar(64) DEFAULT NULL COMMENT 'url描述', 
  PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 
 
-- 数据导出被取消选择。 
-- 导出  表 boot_shrio.u_role 结构 
DROP TABLE IF EXISTS `u_role`; 
CREATE TABLE IF NOT EXISTS `u_role` ( 
  `id` bigint(20) NOT NULL AUTO_INCREMENT, 
  `name` varchar(32) DEFAULT NULL COMMENT '角色名称', 
  `type` varchar(10) DEFAULT NULL COMMENT '角色类型', 
  PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 
 
-- 数据导出被取消选择。 
-- 导出  表 boot_shrio.u_role_permission 结构 
DROP TABLE IF EXISTS `u_role_permission`; 
CREATE TABLE IF NOT EXISTS `u_role_permission` ( 
  `rid` bigint(20) DEFAULT NULL COMMENT '角色ID', 
  `pid` bigint(20) DEFAULT NULL COMMENT '权限ID' 
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 
 
-- 数据导出被取消选择。 
-- 导出  表 boot_shrio.u_user 结构 
DROP TABLE IF EXISTS `u_user`; 
CREATE TABLE IF NOT EXISTS `u_user` ( 
  `id` bigint(20) NOT NULL AUTO_INCREMENT, 
  `nickname` varchar(20) DEFAULT NULL COMMENT '用户昵称', 
  `email` varchar(128) DEFAULT NULL COMMENT '邮箱|登录帐号', 
  `pswd` varchar(32) DEFAULT NULL COMMENT '密码', 
  `create_time` datetime DEFAULT NULL COMMENT '创建时间', 
  `last_login_time` datetime DEFAULT NULL COMMENT '最后登录时间', 
  `status` bigint(1) DEFAULT '1' COMMENT '1:有效,0:禁止登录', 
  PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 
 
-- 数据导出被取消选择。 
-- 导出  表 boot_shrio.u_user_role 结构 
DROP TABLE IF EXISTS `u_user_role`; 
CREATE TABLE IF NOT EXISTS `u_user_role` ( 
  `uid` bigint(20) DEFAULT NULL COMMENT '用户ID', 
  `rid` bigint(20) DEFAULT NULL COMMENT '角色ID' 
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 
-- 正在导出表  boot_shrio.u_permission 的数据:~2 rows (大约) 
/*!40000 ALTER TABLE `u_permission` DISABLE KEYS */; 
INSERT INTO `u_permission` (`id`, `url`, `name`) VALUES 
	(1, 'userInfo/userList', '用户管理'), 
	(2, 'userInfo/userAdd', '用户添加'), 
	(3, 'userInfo/userDel', '用户删除'); 
/*!40000 ALTER TABLE `u_permission` ENABLE KEYS */; 
 
-- 正在导出表  boot_shrio.u_role 的数据:~2 rows (大约) 
/*!40000 ALTER TABLE `u_role` DISABLE KEYS */; 
INSERT INTO `u_role` (`id`, `name`, `type`) VALUES 
	(1, '管理员', '1'), 
	(2, '用户', '2'); 
/*!40000 ALTER TABLE `u_role` ENABLE KEYS */; 
 
-- 正在导出表  boot_shrio.u_role_permission 的数据:~2 rows (大约) 
/*!40000 ALTER TABLE `u_role_permission` DISABLE KEYS */; 
INSERT INTO `u_role_permission` (`rid`, `pid`) VALUES 
	(1, 1), 
	(1, 2), 
	(1, 3); 
/*!40000 ALTER TABLE `u_role_permission` ENABLE KEYS */; 
 
-- 正在导出表  boot_shrio.u_user 的数据:~0 rows (大约) 
/*!40000 ALTER TABLE `u_user` DISABLE KEYS */; 
INSERT INTO `u_user` (`id`, `nickname`, `email`, `pswd`, `create_time`, `last_login_time`, `status`) VALUES 
	(1, 'admin', 'admin@163.com', '1', '2019-04-27 22:44:44', NULL, 1); 
/*!40000 ALTER TABLE `u_user` ENABLE KEYS */; 
 
-- 正在导出表  boot_shrio.u_user_role 的数据:~0 rows (大约) 
/*!40000 ALTER TABLE `u_user_role` DISABLE KEYS */; 
INSERT INTO `u_user_role` (`uid`, `rid`) VALUES 
	(1, 1);

第二步:数据库实体、Mapper文件、Mapper接口、Service接口和Service 实现:

具体请参考:

apache  shrio 依赖jar 文件pom.xml

<!--apache shrio 依赖jar --> 
		<dependency> 
			<groupId>org.apache.shiro</groupId> 
			<artifactId>shiro-spring</artifactId> 
			<version>1.2.5</version> 
		</dependency> 
		<dependency> 
			<groupId>org.apache.shiro</groupId> 
			<artifactId>shiro-ehcache</artifactId> 
			<version>1.2.5</version> 
		</dependency>

boot-shrio-controller 项目涉及apache shrio 配置和用户登入:

package com.zzg.shrio.config; 
 
import java.util.LinkedHashMap; 
import java.util.Map; 
 
import javax.servlet.Filter; 
 
import org.apache.shiro.authc.credential.HashedCredentialsMatcher; 
import org.apache.shiro.spring.LifecycleBeanPostProcessor; 
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; 
import org.apache.shiro.spring.web.ShiroFilterFactoryBean; 
import org.apache.shiro.web.filter.authc.LogoutFilter; 
import org.apache.shiro.web.mgt.DefaultWebSecurityManager; 
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; 
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.context.annotation.DependsOn; 
 
import com.zzg.shrio.realm.ShiroRealm; 
/** 
 * shrio 配置类 
 * @author Administrator 
 * 
 */ 
@Configuration 
public class ShiroConfiguration { 
	 
	// 管理shrio 生命周期 
	@Bean(name = "lifecycleBeanPostProcessor") 
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { 
        return new LifecycleBeanPostProcessor(); 
    } 
	 
	/** 
     * HashedCredentialsMatcher,这个类是为了对密码进行编码的, 
     * 防止密码在数据库里明码保存,当然在登陆认证的时候, 
     * 这个类也负责对form里输入的密码进行编码。 
     */ 
    @Bean(name = "hashedCredentialsMatcher") 
    public HashedCredentialsMatcher hashedCredentialsMatcher() { 
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(); 
        credentialsMatcher.setHashAlgorithmName("MD5"); 
        credentialsMatcher.setHashIterations(2); 
        credentialsMatcher.setStoredCredentialsHexEncoded(true); 
        return credentialsMatcher; 
    } 
     
    /**ShiroRealm,这是个自定义的认证类,继承自AuthorizingRealm, 
     * 负责用户的认证和权限的处理,可以参考JdbcRealm的实现。 
     */ 
    @Bean(name = "shiroRealm") 
    @DependsOn("lifecycleBeanPostProcessor") 
    public ShiroRealm shiroRealm() { 
        ShiroRealm realm = new ShiroRealm(); 
//        realm.setCredentialsMatcher(hashedCredentialsMatcher()); 
        return realm; 
    } 
     
 
//  /** 
//   * EhCacheManager,缓存管理,用户登陆成功后,把用户信息和权限信息缓存起来, 
//   * 然后每次用户请求时,放入用户的session中,如果不设置这个bean,每个请求都会查询一次数据库。 
//   */ 
//  @Bean(name = "ehCacheManager") 
//  @DependsOn("lifecycleBeanPostProcessor") 
//  public EhCacheManager ehCacheManager() { 
//      return new EhCacheManager(); 
//  } 
 
    /** 
     * SecurityManager,权限管理,这个类组合了登陆,登出,权限,session的处理,是个比较重要的类。 
//     */ 
    //SecurityManager 是 Shiro 架构的核心,通过它来链接Realm和用户(文档中称之为Subject.)   
    @Bean(name = "securityManager") 
    public DefaultWebSecurityManager securityManager() { 
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); 
        securityManager.setRealm(shiroRealm()); 
//        securityManager.setCacheManager(ehCacheManager()); 
        return securityManager; 
    } 
     
    /** 
     * ShiroFilterFactoryBean,是个factorybean,为了生成ShiroFilter。 
     * 它主要保持了三项数据,securityManager,filters,filterChainDefinitionManager。 
     */ 
    @Bean(name = "shiroFilter") 
    public ShiroFilterFactoryBean shiroFilterFactoryBean() { 
    	System.out.println("ShiroConfiguration.shirFilter()"); 
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); 
		shiroFilterFactoryBean.setSecurityManager(securityManager()); 
		//拦截器. 
		Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>(); 
		// 配置不会被拦截的链接 顺序判断 
		filterChainDefinitionMap.put("/static/**", "anon"); 
		//配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了 
		filterChainDefinitionMap.put("/logout", "logout"); 
		//<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了; 
		//<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问--> 
		filterChainDefinitionMap.put("/**", "authc"); 
		// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面 
		shiroFilterFactoryBean.setLoginUrl("/login"); 
		// 登录成功后要跳转的链接 
		shiroFilterFactoryBean.setSuccessUrl("/index"); 
 
		//未授权界面; 
		shiroFilterFactoryBean.setUnauthorizedUrl("/403"); 
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); 
		return shiroFilterFactoryBean; 
    } 
     
    /** 
     * DefaultAdvisorAutoProxyCreator,Spring的一个bean,由Advisor决定对哪些类的方法进行AOP代理。 
     */ 
    @Bean 
    @ConditionalOnMissingBean 
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { 
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator(); 
        defaultAAP.setProxyTargetClass(true); 
        return defaultAAP; 
    } 
 
    /** 
     * AuthorizationAttributeSourceAdvisor,shiro里实现的Advisor类, 
     * 内部使用AopAllianceAnnotationsAuthorizingMethodInterceptor来拦截用以下注解的方法。 
     */ 
    @Bean 
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() { 
        AuthorizationAttributeSourceAdvisor aASA = new AuthorizationAttributeSourceAdvisor(); 
        aASA.setSecurityManager(securityManager()); 
        return aASA; 
    } 
} 
package com.zzg.shrio.realm; 
 
import java.util.List; 
import java.util.stream.Collectors; 
 
import org.apache.shiro.SecurityUtils; 
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.authc.UsernamePasswordToken; 
import org.apache.shiro.authz.AuthorizationInfo; 
import org.apache.shiro.authz.SimpleAuthorizationInfo; 
import org.apache.shiro.realm.AuthorizingRealm; 
import org.apache.shiro.session.Session; 
import org.apache.shiro.subject.PrincipalCollection; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.beans.factory.annotation.Autowired; 
 
import com.zzg.entity.Permission; 
import com.zzg.entity.Role; 
import com.zzg.entity.RolePermission; 
import com.zzg.entity.User; 
import com.zzg.entity.UserRole; 
import com.zzg.service.PermissionService; 
import com.zzg.service.RolePermissionService; 
import com.zzg.service.RoleService; 
import com.zzg.service.UserRoleService; 
import com.zzg.service.UserService; 
 
public class ShiroRealm extends AuthorizingRealm { 
	private Logger logger = LoggerFactory.getLogger(this.getClass()); 
 
	@Autowired 
	private UserService userService; 
	@Autowired 
	private PermissionService permissionService; 
	@Autowired 
	private UserRoleService userRoleService; 
	@Autowired 
	private RoleService roleService; 
	@Autowired 
	private RolePermissionService rolePermissionService; 
 
	// 用户赋于相关权限 
	@Override 
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { 
		// TODO Auto-generated method stub 
		logger.info("doGetAuthorizationInfo+" + principalCollection.toString()); 
		User user = userService.getByUserName((String) principalCollection.getPrimaryPrincipal()); 
 
		// 把principals放session中 key=userId value=principals 
		SecurityUtils.getSubject().getSession().setAttribute(String.valueOf(user.getId()), 
				SecurityUtils.getSubject().getPrincipals()); 
 
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); 
		// 赋予角色 
		List<UserRole> userRoles = userRoleService.getByUid(user.getId()); 
		List<Long> list = userRoles.stream().map(UserRole::getRid).collect(Collectors.toList()); 
		List<Role> roles = roleService.getByIds(list); 
		for (Role role : roles) { 
			info.addRole(role.getName()); 
		} 
 
		// 赋予权限 
		List<Long> roleIds = roles.stream().map(Role::getId).collect(Collectors.toList()); 
		List<RolePermission> rolePermissions = rolePermissionService.getByRoleIds(roleIds); 
 
		List<Long> permissionIds = rolePermissions.stream().map(RolePermission::getPid).collect(Collectors.toList()); 
		List<Permission> permissions = permissionService.getByPermissionIds(permissionIds); 
		for (Permission permission : permissions) { 
			info.addStringPermission(permission.getUrl()); 
		} 
		return info; 
	} 
 
	// 用户登入验证 
	@Override 
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) 
			throws AuthenticationException { 
		// TODO Auto-generated method stub 
		logger.info("doGetAuthenticationInfo +" + authenticationToken.toString()); 
		UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; 
		String userName = token.getUsername(); 
		// 输出用户信息(账户和密码) 
		logger.info(userName + token.getPassword()); 
 
		User user = userService.getByUserName(token.getUsername()); 
		if (user != null) { 
			// 设置用户session 
			Session session = SecurityUtils.getSubject().getSession(); 
			session.setAttribute("user", user); 
			return new SimpleAuthenticationInfo(userName, user.getPswd(), getName()); 
		} 
		return null; 
	} 
 
} 

使用Apache shrio 实现权限鉴权业务代码:

package com.zzg.controller; 
 
import java.util.Map; 
 
import javax.servlet.http.HttpServletRequest; 
 
import org.apache.shiro.authc.IncorrectCredentialsException; 
import org.apache.shiro.authc.UnknownAccountException; 
import org.springframework.stereotype.Controller; 
import org.springframework.web.bind.annotation.RequestMapping; 
 
@Controller 
public class HomeController { 
	@RequestMapping({"/","/index"}) 
    public String index() { 
        return "index"; 
    } 
     
    @RequestMapping("/login") 
    public String login(HttpServletRequest request, Map<String, Object> map) { 
    	System.out.println("HomeController.login"); 
 
        // 登录失败从request中获取shiro处理的异常信息。 
        // shiroLoginFailure:就是shiro异常类的全类名. 
        Object exception = request.getAttribute("shiroLoginFailure"); 
        String msg = ""; 
        if (exception != null) { 
            if (UnknownAccountException.class.isInstance(exception)) { 
                System.out.println("账户不存在"); 
                msg = "账户不存在或密码不正确"; 
            } else if (IncorrectCredentialsException.class.isInstance(exception)) { 
                System.out.println("密码不正确"); 
                msg = "账户不存在或密码不正确"; 
            } else { 
                System.out.println("其他异常"); 
                msg = "其他异常"; 
            } 
        } 
 
        map.put("msg", msg); 
        // 此方法不处理登录成功,由shiro进行处理. 
        return "login"; 
    } 
     
    @RequestMapping("/403") 
    public String unauthorizedRole(){ 
        System.out.println("------没有权限-------"); 
        return "403"; 
    } 
 
} 
package com.zzg.controller; 
 
import org.apache.shiro.authz.annotation.RequiresPermissions; 
import org.springframework.stereotype.Controller; 
import org.springframework.web.bind.annotation.RequestMapping; 
 
@Controller 
@RequestMapping("/userInfo") 
public class UserInfoController { 
	/** 
     * 用户查询. 
     * @return 
     */ 
    @RequestMapping("/userList") 
    @RequiresPermissions("userInfo/userList")//权限管理; 
    public String userInfo(){ 
        return "userInfo"; 
    } 
 
    /** 
     * 用户添加; 
     * @return 
     */ 
    @RequestMapping("/userAdd") 
    @RequiresPermissions("userInfo/userAdd")//权限管理; 
    public String userInfoAdd(){ 
        return "userInfoAdd"; 
    } 
 
    /** 
     * 用户删除; 
     * @return 
     */ 
    @RequestMapping("/userDel") 
    @RequiresPermissions("userInfo/userDel")//权限管理; 
    public String userDel(){ 
        return "userInfoDel"; 
    } 
} 

springboot +thymelf 具体参考:

声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

发表评论
搜索
KIKK导航

KIKK导航

排行榜
关注我们

一个IT知识分享的公众号