- 前段时间看到的springboot和shiro整合的视频,现特意在此进行展示出来,方便以后来进行查看,看过的朋友点个赞是最好的,自己加油!
- 说起整合,必须要搭建的是springboot的环境,以及进行shiro整合包的导入,项目是做的mavne项目,后期会陆续推送springboot与websocket的整合,springboot全局异常处理,springboot与quartz整合,springboot中AOP的处理,springboot与图片验证码整合,springboot与redis整合,springboot中cookie存储token以及redis中存储token的工具类,springboot文件的上传与下载。
- springmvc的注解使用,mysql读写分离的代码,数据库账号密码加密。赞时想到的就这么些,后面会陆续更新!!!
- 也需要进行博客排榜的好看,文章样式会随时改变。
- 话不多说,直接上sql,以及springboot与shiro整合类,以及所对应的自定义realm类。
- 添加model类
- User表,一个用户对应多个角色,@Data是装了lombok插件的一个属性,替代get,set,toString方法等,不清楚的话,各位具体查下。
-
/** * @program: shiro * @description: 用户 * @author: Join * @create: 2018-12-10 22:29 **/ @Data public class User { private int uid; private String username; private String password; private Set<Role> roles = new HashSet<>(); }
- Permission表
-
@Data public class Permission { private int pid; private String name; private String url; }
-
- Role表:一个角色有多个用户,一个角色有多个权限
-
@Data public class Role { private int rid; private String rname; private Set<User> userSet = new HashSet<>(); private Set<Permission> permissions = new HashSet<>(); }
-
- 先添加pom文件
<?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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.jiaolin</groupId> <artifactId>shiromd5</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>shiromd5</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.20</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.4</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.2.3.RELEASE</version> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.20</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <snapshots> <enabled>true</enabled> </snapshots> </repository> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> <pluginRepository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> </project>
-
/* Navicat Premium Data Transfer Source Server : localhost Source Server Type : MySQL Source Server Version : 50722 Source Host : localhost:3306 Source Schema : apache_shiro Target Server Type : MySQL Target Server Version : 50722 File Encoding : 65001 Date: 17/12/2018 12:19:21 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for permission -- ---------------------------- DROP TABLE IF EXISTS `permission`; CREATE TABLE `permission` ( `pid` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', `url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '', PRIMARY KEY (`pid`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of permission -- ---------------------------- INSERT INTO `permission` VALUES (1, 'add', ''); INSERT INTO `permission` VALUES (2, 'delete', ''); INSERT INTO `permission` VALUES (3, 'edit', ''); INSERT INTO `permission` VALUES (4, 'query', ''); -- ---------------------------- -- Table structure for permission_role -- ---------------------------- DROP TABLE IF EXISTS `permission_role`; CREATE TABLE `permission_role` ( `rid` int(11) NOT NULL, `pid` int(11) NOT NULL, INDEX `idx_rid`(`rid`) USING BTREE, INDEX `idx_pid`(`pid`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of permission_role -- ---------------------------- INSERT INTO `permission_role` VALUES (1, 1); INSERT INTO `permission_role` VALUES (1, 2); INSERT INTO `permission_role` VALUES (1, 3); INSERT INTO `permission_role` VALUES (1, 4); INSERT INTO `permission_role` VALUES (2, 1); INSERT INTO `permission_role` VALUES (2, 4); -- ---------------------------- -- Table structure for role -- ---------------------------- DROP TABLE IF EXISTS `role`; CREATE TABLE `role` ( `rid` int(11) NOT NULL AUTO_INCREMENT, `rname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', PRIMARY KEY (`rid`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of role -- ---------------------------- INSERT INTO `role` VALUES (1, 'admin'); INSERT INTO `role` VALUES (2, 'customer'); -- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `uid` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', PRIMARY KEY (`uid`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of user -- ---------------------------- INSERT INTO `user` VALUES (1, 'admin', 'c41d7c66e1b8404545aa3a0ece2006ac'); INSERT INTO `user` VALUES (2, 'demo', '376204ce2cde0c12bc1ac7ff3651bd93'); -- ---------------------------- -- Table structure for user_role -- ---------------------------- DROP TABLE IF EXISTS `user_role`; CREATE TABLE `user_role` ( `uid` int(11) NOT NULL, `rid` int(11) NOT NULL, INDEX `idx_uid`(`uid`) USING BTREE, INDEX `idx_rid`(`rid`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of user_role -- ---------------------------- INSERT INTO `user_role` VALUES (1, 1); INSERT INTO `user_role` VALUES (2, 2); SET FOREIGN_KEY_CHECKS = 1;
-
自定义realm类,需要继承 AuthorizingRealm
package com.jiaolin.shiro.config; import com.jiaolin.shiro.model.Permission; import com.jiaolin.shiro.model.Role; import com.jiaolin.shiro.model.User; import com.jiaolin.shiro.service.UserService; 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.apache.shiro.util.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import java.util.ArrayList; import java.util.List; import java.util.Set; /** * @program: shiro * @description: 自定义认证器 * @author: Join * @create: 2018-12-10 23:24 **/ public class AuthRealm extends AuthorizingRealm { @Autowired private UserService userService; /** * @Description: 授权 1 拿到对应的用户,根据用户拿到角色(admin,customer) * 和权限的名字(增删改查) * @Param: [principalCollection] * @return: org.apache.shiro.authz.AuthorizationInfo * @Author: Join * @Date: 23:26 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) { User user = (User) principal.fromRealm(this.getClass().getName()).iterator().next(); Set<Role> roles = user.getRoles(); List<String> roleList = new ArrayList<>(); List<String> permissionList = new ArrayList<>(); if (!CollectionUtils.isEmpty(roles)) { for (Role role : roles) { roleList.add(role.getRname()); Set<Permission> permissions = role.getPermissions(); if (!CollectionUtils.isEmpty(permissions)) { for (Permission permission : permissions) { permissionList.add(permission.getName()); } } } } SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addRoles(roleList); info.addStringPermissions(permissionList); return info; } /** * @Description: 认证 * @Param: [authenticationToken] * @return: org.apache.shiro.authc.AuthenticationInfo * @Author: Join * @Date: 23:26 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { //token携带了用户信息 UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token; //获取前端输入的用户名 String userName = usernamePasswordToken.getUsername(); //根据用户名查询数据库中对应的记录 User user = userService.findUserByUsername(userName); //当前realm对象的name String realmName = getName(); //盐值 ByteSource credentialsSalt = ByteSource.Util.bytes(user.getUsername()); //封装用户信息,构建AuthenticationInfo对象并返回 AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user, user.getPassword(), credentialsSalt, realmName); return authcInfo; } }
-
然后在进行shiro配置
@Configuration public class ShiroConfig { /** * 密码校验规则HashedCredentialsMatcher * 这个类是为了对密码进行编码的 , * 防止密码在数据库里明码保存 , 当然在登陆认证的时候 , * 这个类也负责对form里输入的密码进行编码 * 处理认证匹配处理器:如果自定义需要实现继承HashedCredentialsMatcher */ /** * @Description: 下面为添加的 * @Param: [] * @return: HashedCredentialsMatcher * @Author: Join * @Date: 2018/12/13 */ @Bean("hashedCredentialsMatcher") public HashedCredentialsMatcher hashedCredentialsMatcher() { HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(); //指定加密方式为MD5 credentialsMatcher.setHashAlgorithmName("MD5"); //加密次数 credentialsMatcher.setHashIterations(1024); credentialsMatcher.setStoredCredentialsHexEncoded(true); return credentialsMatcher; } @Bean("authRealm") @DependsOn("lifecycleBeanPostProcessor")//可选 public AuthRealm authRealm(@Qualifier("hashedCredentialsMatcher") HashedCredentialsMatcher matcher) { AuthRealm authRealm = new AuthRealm(); authRealm.setAuthorizationCachingEnabled(false); authRealm.setCredentialsMatcher(matcher); return authRealm; } /** * 定义安全管理器securityManager,注入自定义的realm * @param authRealm * @return */ @Bean("securityManager") public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm) { DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); manager.setRealm(authRealm); return manager; } /** * 定义shiroFilter过滤器并注入securityManager * @param securityManager * @return */ @Bean("shiroFilter") public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager securityManager) { ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); bean.setSecurityManager(securityManager); bean.setLoginUrl("/login"); bean.setSuccessUrl("/index"); bean.setUnauthorizedUrl("/unauthorized"); LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/index", "authc"); filterChainDefinitionMap.put("/login", "anon"); filterChainDefinitionMap.put("/loginUser", "anon"); //角色为admin的用户才能访问admin网页 filterChainDefinitionMap.put("/admin", "roles[admin]"); //权限为edit的角色才能访问edit页面 filterChainDefinitionMap.put("/edit", "perms[edit]"); filterChainDefinitionMap.put("/druid/**", "anon"); //另外的页面需要用户进行登录才能访问 filterChainDefinitionMap.put("/**", "user"); bean.setFilterChainDefinitionMap(filterChainDefinitionMap); return bean; } /** * Spring的一个bean , 由Advisor决定对哪些类的方法进行AOP代理 . * @return */ @Bean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator(); creator.setProxyTargetClass(true); return creator; } /** * 配置shiro跟spring的关联 * @param securityManager * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; } /** * lifecycleBeanPostProcessor是负责生命周期的 , 初始化和销毁的类 * (可选) */ @Bean("lifecycleBeanPostProcessor") public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } public static void main(String[] args) { String hashAlgorithName = "MD5"; String password = "123"; int hashIterations = 1024;//加密次数 ByteSource credentialsSalt = ByteSource.Util.bytes("admin"); Object obj = new SimpleHash(hashAlgorithName, password, credentialsSalt, hashIterations); System.out.println(obj); } }
-
spring和shiro的配置算完成了,然后在来看看登录与登出的操作怎么写,页面的话,后面在进行写进来。
@Controller public class UserController { /** * @Description: 用户登录 登录成功返回index 失败跳转到login * @Param: [username, password] * @return: java.lang.String * @Author: Join * @Date: 23:13 */ @RequestMapping("/loginUser") public String login(@RequestParam("username") String username, @RequestParam("password") String password, HttpSession session) { UsernamePasswordToken token = new UsernamePasswordToken(username, password); Subject subject = SecurityUtils.getSubject(); try { subject.login(token); //获取主体 User user = (User) subject.getPrincipal(); //并设置在session中 session.setAttribute("user", user); return "index"; } catch (Exception e) { e.printStackTrace(); return "login"; } } /** * @Description: 跳转登录页面 * @Param: [] * @return: java.lang.String * @Author: Join * @Date: 23:20 */ @RequestMapping("/login") public String login() { return "login"; } /** * @Description: admin登录成功 * @Param: [] * @return: java.lang.String * @Author: Join * @Date: 23:20 */ @RequestMapping("/admin") @ResponseBody public String admin() { return "admin success"; } /** * @Description: 跳转到index页面 * @Param: [] * @return: java.lang.String * @Author: Join * @Date: 23:20 */ @RequestMapping("/index") public String index() { return "index"; } /** * @Description: 登出 * @Param: [] * @return: java.lang.String * @Author: Join * @Date: 23:14 */ @RequestMapping("/logout") public String logout() { Subject subject = SecurityUtils.getSubject(); if (subject != null) { subject.logout(); } return "login"; } /** * @Description: 授权不成功跳转页面 * @Param: [] * @return: java.lang.String * @Author: Join * @Date: 23:19 */ @RequestMapping("/unauthorized") public String unauthorized() { return "unauthorized"; } /** * @Description: 编辑成功 * @Param: [] * @return: java.lang.String * @Author: Join * @Date: 23:18 */ @RequestMapping("/edit") @ResponseBody public String edit() { return "edit success"; } }
-
获取认证的时候需要调用service,以及dao层,先添出来,接口就不添了。
-
@Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public User findUserByUsername(String name) { return userMapper.findUserByUsername(name); } }
-
public interface UserMapper { User findUserByUsername(String username); }
-
<?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.jiaolin.shiro.mapper.UserMapper"> <resultMap id="baseUserMap" type="com.jiaolin.shiro.model.User"> <id property="uid" column="uid"/> <result property="username" column="username"/> <result property="password" column="password"/> <collection property="roles" ofType="com.jiaolin.shiro.model.Role"> <id property="rid" column="rid"/> <result property="rname" column="rname"/> <collection property="permissions" ofType="com.jiaolin.shiro.model.Permission"> <id property="pid" column="pid"/> <result property="name" column="name"/> <result property="url" column="url"/> </collection> </collection> </resultMap> <select id="findUserByUsername" parameterType="string" resultMap="baseUserMap"> SELECT u.*,r.*,p.* FROM user u INNER JOIN user_role ur ON u.uid=ur.uid INNER JOIN role r ON r.rid=ur.rid INNER JOIN permission_role pr ON pr.rid=r.rid INNER JOIN permission p ON p.pid=pr.pid WHERE u.username=#{username,jdbcType=VARCHAR} </select> </mapper>
-
-
最后的话,在项目的properties进行全局配置,以及页面的布置,
## database ## spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/apache_shiro?characterEncoding=UTF-8 spring.datasource.username=root spring.datasource.password=root server.port=8081 ## mybatis ## mybatis.mapper-locations=mapper/*.xml mybatis.type-aliases-package=com.jiaolin.shiro.model ## jsp ## spring.mvc.view.prefix=/page/ spring.mvc.view.suffix=.jsp
-
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>index</title> </head> <body> <h3>欢迎你登录 ${user.username}</h3> </body> </html> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Login</title> </head> <body> <h2>欢迎登陆</h2> <form action="/loginUser" method="post"> <input type="text" name="username"> <br> <input type="password" name="password"> <br> <input type="submit" value="提交"> </form> </body> </html> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>UnAuthorized</title> </head> <body> <h3>UnAuthorized</h3> </body> </html>
以上的这些都是JSP页面,为了简便,全部打上了html标签了。springboot项目中默认页面是放到webapp中,和resources同级,懂一点常识的人都知道,这上面的博客为一篇最简单的博客,没做多大的校验,也没有所谓的弄redis集群版,后续会连续发布其余的整合,也是相对较简单的入门篇,源码的话,就不看了,虽然看懂一点点,毕竟我也是一菜鸟,经过本人测试是OK的,爱学习的人欢迎留言咨询,不喜的人也勿喷,如要转载,请经过本人同意。后面做的记录,跟博客没有一点点关联,建议不要看,只是我每天上下班挤地铁时候看的2个小时的书籍做的一点感想。做下记录,以便给我自己脑海中留点记录。
-
最后,在此对前面2天看过的书籍,学习的精进,其中回忆的两点进行记录,
-
1-3-12学习法,意思就是说坚持1个月,3个月,12个月,
-
1-3-10学习法,意思就是坚持1年,3年,10年,这也就是所说的10年学习法,10年之后,你必定是一个不一样的自己,加油。
-
适当学习法:
-
输入输出法:以输入和输出的比列来算,3:7的概率来讲,这是所谓的黄金比例,如果没有输出,就减少输入。
-
-
对于精英这样用脑不会累写下自我感言
-
每天设定一个小目标,想办法完成。
-
完成这个小目标后,在继续指定更大的目标。
-
完成目标后,给自己一些奖赏。
-
目标不要不切实际,那样会坚持不下去的。加油。
-
sprinboot整合shiro,MD5加密,加盐
最新推荐文章于 2022-03-27 00:15:00 发布