SpringBoot 集成Shrio 用户权限管理

本文介绍如何在SpringBoot项目中集成Apache Shiro框架,实现用户认证、权限管理和会话控制。涵盖数据库表设计、实体类、Mapper、Service及Shiro配置,包括自定义Realm和过滤器设置。
摘要由CSDN通过智能技术生成

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 具体参考:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值