springBoot shiro整合
2018-03-12 15:45
561 查看
Shiro是一个权限框架,他提供了很方便的权限认证和登录的功能。而springboot必然提供了和shiro整合的功能,接下来就用springboot结合mybatis整合shiro。
Step1. 准备数据库表 这里主要涉及五张表:用户表(user),角色表(role),权限表(permission),用户-角色表(user_role),角色-权限表 (role_permission)。 注意:用户和角色是多对多的关系,角色和权限是多对多的关系。
用户表的字段有:id(主键),username(用户名),password(密码),salt(在密码加密的时候会用到)。 角色表的字段有:id(主键),rolename(角色名称)。 权限表的字段有:id(主键),permissionname(权限名称)。 用户
4000
-角色表的字段有:id(主键),userId(用户id), roleId(角色id)。 角色-权限表的字段有:id(主键),roleId(角色id), permissionId(权限id)。
Step2. 新建一个springBoot项目,导入以下的依赖
Step4. 建立和表相对应的实体类
public class Role {
private Integer id;
private String roleName;
}
MyShiroRelam的代码如下:
ShiroConfig类的代码如下:
下面是自己定义的util类
最后就是controller类的调用
Step1. 准备数据库表 这里主要涉及五张表:用户表(user),角色表(role),权限表(permission),用户-角色表(user_role),角色-权限表 (role_permission)。 注意:用户和角色是多对多的关系,角色和权限是多对多的关系。
用户表的字段有:id(主键),username(用户名),password(密码),salt(在密码加密的时候会用到)。 角色表的字段有:id(主键),rolename(角色名称)。 权限表的字段有:id(主键),permissionname(权限名称)。 用户
4000
-角色表的字段有:id(主键),userId(用户id), roleId(角色id)。 角色-权限表的字段有:id(主键),roleId(角色id), permissionId(权限id)。
Step2. 新建一个springBoot项目,导入以下的依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>shiroProjectDemo</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>jar</packaging> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> </parent> <properties> <java.version>1.8</java.version> <shiro.version>1.3.2</shiro.version> <commons-lang3>3.7</commons-lang3> <druid.version>1.1.6</druid.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>${commons-lang3}</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>${druid.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>Step3. 对数据库连接池进行配置。我采用的是阿里巴巴的Druid数据源,在application.yml中对他进行相关配置。
#默认使用配置 spring: profiles: active: dev #公共配置与profiles选择无关 mybatis: typeAliasesPackage: com.example.demo.dao mapperLocations: classpath:mapper/*.xml --- #开发配置 spring: profiles: dev datasource: url: jdbc:mysql://localhost:3306/shirodatabase?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver session: store-type: none注:还应该在数据库连接池的配置类完成对数据库连接池的配置(这里不做过多的描述)。
Step4. 建立和表相对应的实体类
public class User { private Integer id; private String username; private String password; private String salt; //用户的角色id private List<String> roleIds; }
public class Role {
private Integer id;
private String roleName;
}
public class Permission { private Integer id; private String permissionName; }
public class UserRole { private Integer id; private String userId; private String roleId; }
public class RolePermission { private Integer id; private String roleName; private String permissionName; }接着就可以书写mapper了,mapper所在的位置要和Application类中所配置的包扫描的位置保持一致。userMapper.xml如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper e80e namespace="com.example.demo.dao.UserMapper"> <resultMap id="BaseResultMap" type="com.example.demo.dao.entity.User"> <id column="id" jdbcType="INTEGER" property="id" /> <result column="username" jdbcType="VARCHAR" property="username" /> <result column="password" jdbcType="VARCHAR" property="password" /> <result column="salt" jdbcType="VARCHAR" property="salt" /> </resultMap> <sql id="Base_Column_List"> id, username, password , salt </sql> <insert id="insertSelective" parameterType="com.example.demo.dao.entity.User"> insert into user <trim prefix="(" suffix=")" suffixOverrides=","> <if test="id != null"> id, </if> <if test="username != null"> username, </if> <if test="password != null"> password, </if> <if test="salt != null"> salt, </if> </trim> <trim prefix="values (" suffix=")" suffixOverrides=","> <if test="id != null"> #{id,jdbcType=INTEGER}, </if> <if test="username != null"> #{username,jdbcType=VARCHAR}, </if> <if test="password != null"> #{password,jdbcType=VARCHAR}, </if> <if test="salt != null"> #{salt,jdbcType=VARCHAR}, </if> </trim> </insert> <select id="getUser" resultMap="BaseResultMap" resultType="java.lang.String"> SELECT <include refid="Base_Column_List" /> FROM user WHERE username = #{username,jdbcType = VARCHAR} </select> </mapper>roleMapper.xml如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.demo.dao.RoleMapper"> <resultMap id="BaseResultMap" type="com.example.demo.dao.entity.Role"> <id column="id" jdbcType="INTEGER" property="id" /> <result column="roleId" jdbcType="VARCHAR" property="roleId" /> </resultMap> <select id="listByUserId" parameterType="java.lang.Integer" resultMap="BaseResultMap"> SELECT role.* FROM role,user_role WHERE role.id = user_role.roleId AND userId = #{userId,jdbcType = INTEGER} </select> </mapper>permissionMapper.xml如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.demo.dao.PermissionMapper"> <resultMap id="BaseResultMap" type="com.example.demo.dao.entity.Permission"> <id column="id" jdbcType="INTEGER" property="id" /> <result column="permissionname" jdbcType="VARCHAR" property="permissionName" /> </resultMap> <sql id="Base_Column_List"> id,permissionname </sql> <select id="listPermissionByUserId" parameterType="java.lang.Integer" resultMap="BaseResultMap"> select distinct p.* from permission p inner join role_permission rp on p.id = rp.permissionId inner join role_user ru on ru.id = rp.roleId where ru.userId = #{userId} </select> </mapper>在service层完成对业务层mapper的调用:
package com.example.demo.service.impl; import com.example.demo.constants.UserConstants; import com.example.demo.dao.UserMapper; import com.example.demo.dao.UserRoleMapper; import com.example.demo.dao.entity.User; import com.example.demo.service.UserService; import org.apache.commons.codec.digest.DigestUtils; import org.apache.shiro.crypto.hash.SimpleHash; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import java.util.List; import java.util.UUID; @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Autowired private UserRoleMapper userRoleMapper; @Override public User getUser(String name) { return userMapper.getUser(name); } @Override public String passwordEncoder(String credentials, String salt) { Object object = new SimpleHash("MD5", credentials, salt, UserConstants.HASH_ITERATIONS); return object.toString(); } @Override public int addUser(User user) { user.setSalt(DigestUtils .md5Hex(UUID.randomUUID().toString() + System.currentTimeMillis() + UUID.randomUUID().toString())); user.setPassword(passwordEncoder(user.getPassword(), user.getSalt())); //添加用户 int i = userMapper.insertSelective(user); int j = saveUserRoles(user.getId(), user.getRoleIds()); if(i!=0 && j!=0){ return 1; } return 0; } private int saveUserRoles(Integer userId, List<String> roleIds) { String username = String.valueOf(userId); int i=0; if (roleIds != null) { userRoleMapper.deleteRoleByUserId(username); if (!CollectionUtils.isEmpty(roleIds)) { i = userRoleMapper.saveUserRoles(username, roleIds); } } return i; } }然后就是重点了!我们需要建立两个类MyShiroRelam和shiroConfig。
MyShiroRelam的代码如下:
package com.example.demo.config; import com.example.demo.dao.PermissionMapper; import com.example.demo.dao.RoleMapper; import com.example.demo.dao.entity.Permission; import com.example.demo.dao.entity.Role; import com.example.demo.dao.entity.User; import com.example.demo.service.UserService; import com.example.demo.utils.SpringUtil; import com.example.demo.utils.UserUtil; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.ByteSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils; import java.util.List; import java.util.Set; import java.util.stream.Collectors; public class MyShiroRealm extends AuthorizingRealm { private static final Logger log = LoggerFactory.getLogger("adminLogger"); @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 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); return authenticationInfo; } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { log.debug("权限配置"); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); User user = UserUtil.getCurrentUser(); //TODO 获得用户角色 List<Role> roles = SpringUtil.getBean(RoleMapper.class).listByUserId(user.getId()); Set<String> roleNames = roles.stream().map(Role::getRoleName).collect(Collectors.toSet()); authorizationInfo.setRoles(roleNames); //TODO 获得用户权限 List<Permission> permissionList = SpringUtil.getBean(PermissionMapper.class).listPermissionByUserId(user.getId()); UserUtil.setPermissionSession(permissionList); Set<String> permissions = permissionList.stream().filter(p -> !StringUtils.isEmpty(p.getPermissionName())) .map(Permission::getPermissionName).collect(Collectors.toSet()); authorizationInfo.setStringPermissions(permissions); return authorizationInfo; } }
ShiroConfig类的代码如下:
package com.example.demo.config; import com.example.demo.constants.UserConstants; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.cache.ehcache.EhCacheManager; import org.apache.shiro.mgt.SecurityManager; 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.mgt.DefaultWebSecurityManager; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import java.util.LinkedHashMap; import java.util.Map; @Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); // 拦截器. Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); //过滤掉不需要拦截的请求 //这不需要登录就可以访问的请求 filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/fonts/**", "anon"); filterChainDefinitionMap.put("/img/**", "anon"); filterChainDefinitionMap.put("/js/**", "anon"); filterChainDefinitionMap.put("/login", "anon"); filterChainDefinitionMap.put("/insertUser", "anon"); filterChainDefinitionMap.put("/files/*", "anon"); //这登录之后才可以访问的请求 filterChainDefinitionMap.put("/**", "authc"); // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面 shiroFilterFactoryBean.setLoginUrl("/login.html"); //登录成功后到达的页面 shiroFilterFactoryBean.setSuccessUrl("/index.html"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager() { EhCacheManager cacheManager = new EhCacheManager(); DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //设置realm. securityManager.setRealm(myShiroRealm()); //注入缓存管理器,这个如果执行多次,也是同样的一个对象; securityManager.setCacheManager(cacheManager); return securityManager; } @Bean public MyShiroRealm myShiroRealm() { MyShiroRealm myShiroRealm = new MyShiroRealm(); // 必须设置 SecurityManager myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher()); return myShiroRealm; } /** * 凭证匹配器 * * @return */ @Bean public HashedCredentialsMatcher hashedCredentialsMatcher() { HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); hashedCredentialsMatcher.setHashAlgorithmName("md5");// 散列算法:这里使用MD5算法; hashedCredentialsMatcher.setHashIterations(UserConstants.HASH_ITERATIONS); return hashedCredentialsMatcher; } /** * Shiro生命周期处理器 * * @return */ @Bean public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } /** * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions), * 需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证 * * @return */ @Bean @DependsOn({ "lifecycleBeanPostProcessor" }) public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); advisorAutoProxyCreator.setProxyTargetClass(true); return advisorAutoProxyCreator; } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } }
下面是自己定义的util类
package com.example.demo.utils; import com.example.demo.constants.UserConstants; import com.example.demo.dao.entity.Permission; import com.example.demo.dao.entity.User; import org.apache.shiro.SecurityUtils; import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; import java.util.List; public class UserUtil { public static User getCurrentUser() { User user = (User) getSession().getAttribute(UserConstants.LOGIN_USER); return user; } public static void setUserSession(User user) { getSession().setAttribute(UserConstants.LOGIN_USER, user); } @SuppressWarnings("unchecked") public static List<Permission> getCurrentPermissions() { List<Permission> list = (List<Permission>) getSession().getAttribute(UserConstants.USER_PERMISSIONS); return list; } public static void setPermissionSession(List<Permission> list) { getSession().setAttribute(UserConstants.USER_PERMISSIONS, list); } public static Session getSession() { Subject currentUser = SecurityUtils.getSubject(); Session session = currentUser.getSession(); return session; } }
package com.example.demo.utils; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; /** * spring获取bean工具类 * * */ @Component public class SpringUtil implements ApplicationContextAware { private static ApplicationContext applicationContext = null; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringUtil.applicationContext = applicationContext; } public static <T> T getBean(Class<T> cla) { return applicationContext.getBean(cla); } public static <T> T getBean(String name, Class<T> cal) { return applicationContext.getBean(name, cal); } public static String getProperty(String key) { return applicationContext.getBean(Environment.class).getProperty(key); } }
最后就是controller类的调用
package com.example.demo.controller; import com.example.demo.dao.entity.User; import com.example.demo.service.UserService; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; /** * Created by chendai on 2018/3/10. */ @RestController public class UserController { @Autowired private UserService userService; /** * 用户注册 */ @PostMapping(value = "/insertUser") public Map<String,Object> addUser(@RequestBody User user){ Map<String,Object> messageMap = new HashMap<>(); int i = userService.addUser(user); if(i !=0){ messageMap.put("message","success"); }else{ messageMap.put("message","failed"); } return messageMap; } /** * 登录 */ @PostMapping(value = "login") public Map<String,String> login(@RequestParam("username") String username, @RequestParam("password")String password){ Map<String,String> messageMap = new HashMap<>(); try{ UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username,password); SecurityUtils.getSubject().login(usernamePasswordToken); messageMap.put("message","登录成功"); }catch (Exception e){ String message = e.getMessage(); messageMap.put("message",message); } return messageMap; } }这样就完成了springBoot 、myBatis和shiro的整合。
相关文章推荐
- SpringBoot整合mybatis、shiro、redis实现基于数据库的细粒度动态权限管理系统实例(转)
- springboot 整合shiro
- Spring Boot+Shiro+Redis(redisson)整合时,采用内嵌tomcat启动错误原因分析
- spring boot shiro整合
- springboot整合shiro应用
- Spring Boot Shiro权限管理--自定义 FormAuthenticationFilter验证码整合
- springboot shiro 整合
- 补习系列(6)- springboot 整合 shiro 一指禅
- SpringBoot学习:整合shiro(验证码功能和登录次数限制功能)
- Spring Boot+Shiro+Redis(redisson)整合时,采用内嵌tomcat启动错误原因分析
- Spring boot项目整合thymeleaf和shiro
- springboot整合shiro-登录认证和权限管理
- springboot(十四):springboot整合shiro-登录认证和权限管理
- SpringBoot+shiro整合学习之登录认证和权限控制
- springboot shiro 整合
- springboot thymeleaf和shiro标签整合
- SpringBoot整合mybatis、shiro、redis实现基于数据库的细粒度动态权限管理系统实例
- spring boot整合shiro引用配置文件配置是出现的问题
- Spring Boot+Shiro+Redis(redisson)整合时,采用内嵌tomcat启动错误原因分析
- springboot整合shiro