springboot + shiro + mysql + mybatis 工程快速搭建

1. 新建 springboot 工程

2. 随便起个名字

 

 3. 初始化工程

 

 4. 导入 shiro 和 thymeleaf 依赖

        <!-- thymeleaf依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- thymeleaf依赖结束 -->
        <!-- shiro依赖 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.3.2</version>
        </dependency>
        <!-- shiro依赖结束 -->

5. 编写 application.yml 配置文件

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url:
jdbc:mysql:///test?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=true
  username: root password: root thymeleaf: encoding: UTF-8

6. 新建一个 User 类

import lombok.Data;

@Data
public class User {
    private Integer id;
    private String username;
    private String password;
    private String prems;
}

7. 创建 User 业务层与持久层

 UserService

import com.example.exam01.entity.User;

/**
 * User 业务层
 */
public interface UserService {
    User findByName(String username);
}

UserServiceImpl

import com.example.exam01.dao.UserDao;
import com.example.exam01.entity.User;
import com.example.exam01.service.UserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * User 业务层实现类
 */
@Service
@Transactional
public class UserServiceImpl implements UserService {

    @Resource
    private UserDao userDao;

    @Override
    public User findByName(String username) {
        return userDao.findByName(username);
    }
}

UserDao

import com.example.exam01.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;

/**
 * User 持久层
 */
@Repository
@Mapper
public interface UserDao {

    @Select("SELECT * FROM user WHERE username = #{username}")
    User findByName(@Param("username") String username);
}

8. 新建一个 ShiroConfig 配置文件类

import com.example.exam01.shiro.realm.MyRealm;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * shiro 配置类
 */
@Configuration
public class ShiroConfig {
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/toLogin");
        shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");

        // 定义一个map集合用来存放访问规则
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        /*
                Shiro内置过滤器, 可以实现权限相关的拦截器
                常用的过滤器:
                anon: 无需认证(登录)可以访问
                authc: 必须认证才可以访问
                user: 使用 rememberMe 的功能可以直接访问
                perms: 该资源必须得到资源权限才可以访问
                role: 该资源必须得到角色权限才可以访问
         */
        // 注意配置顺序
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/", "anon");
        filterChainDefinitionMap.put("/admin/**", "perms[user:admin]");
        filterChainDefinitionMap.put("/user/**", "authc");
        filterChainDefinitionMap.put("/logout", "authc");
        //主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截 剩余的都需要认证
        filterChainDefinitionMap.put("/**", "authc");
        // 将规则写入 shiroFilterFactoryBean 中
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;

    }

    /**
     * 获取 SecurityManager
     * @return
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
        defaultSecurityManager.setRealm(myRealm());
        return defaultSecurityManager;
    }

    /**
     * 获取 MyRealm
     * @return
     */
    @Bean
    public MyRealm myRealm() {
        MyRealm myRealm = new MyRealm();
        return myRealm;
    }
}

9. 新建一个 Realm 类

import com.example.exam01.entity.User;
import com.example.exam01.service.UserService;
import org.apache.shiro.SecurityUtils;
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.subject.Subject;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.Set;

/**
 * realm类
 */
public class MyRealm extends AuthorizingRealm {

    @Resource
    private UserService userService;
    /**
     * 授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // 获取当前登录用户
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipal();

        // 获取 SimpleAuthorizationInfo 对象写入授权规则
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        // 创建一个 set 集合用来保存当前用户的授权信息
        Set<String> stringSet = new HashSet<>();
        stringSet.add(user.getPrems());

        // 将授权信息写入 SimpleAuthorizationInfo 对象中
        info.setStringPermissions(stringSet);
        return info;
    }

    /**
     * 认证
     * @param auToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auToken) throws AuthenticationException {
        // AuthenticationToken 强转 UsernamePasswordToken
        UsernamePasswordToken token = (UsernamePasswordToken) auToken;
        // 从数据库获取用户信息
        User user = userService.findByName(token.getUsername());
        return new SimpleAuthenticationInfo(user, user.getPassword(),getName());
    }
}

 10. 编写 controller 层

 LoginController

package com.example.exam01.controller;

import com.example.exam01.entity.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 *  Login 控制类
 */

@Controller
public class LoginController {

    // 跳转登录页面
    @RequestMapping("/toLogin")
    public String toLogin(){
        return "login";
    }

    // 执行登录方法
    @RequestMapping("/login")
    public String login(User user, Model model){
        // 执行加密算法
        SimpleHash md5 = new SimpleHash("MD5",user.getPassword(),null,1);
        String password = md5.toString();

        // 获取 subject 对象
        Subject subject = SecurityUtils.getSubject();

        // 准备 token 令牌
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(),password);

        // 定义一个返回提示信息容器
        String msg = null;
        // 执行认证登录
        try{
            subject.login(token);
        } catch (UnknownAccountException uae) {
            msg = "未知账户";
        } catch (IncorrectCredentialsException ice) {
            msg = "密码不正确";
        } catch (LockedAccountException lae) {
            msg = "账户已锁定";
        } catch (ExcessiveAttemptsException eae) {
            msg = "用户名或密码错误次数过多";
        } catch (AuthenticationException ae) {
            msg = "用户名或密码不正确";
        }

        // 判断登录是否成功
        if (subject.isAuthenticated()) {
            return "main";
        } else {
            token.clear();
            // 写入返回 tips
            model.addAttribute("msg",msg);
            return "login";
        }
    }

    // 执行登出方法
    @RequestMapping("/logout")
    public String logout(){
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return "login";
    }

    // 跳转错误页面
    @RequestMapping("/noAuth")
    public String noAuth(){
        return "noAuth";
    }
}

UserController

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("list")
    public String list(){
        return "/user/userList";
    }
}

AdminController

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/admin")
public class AdminController {

    @RequestMapping("/list")
    public String list(){
        return "/admin/adminList";
    }
}

11. 编写 HTML 页面

 

 login.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<h3 th:text="${msg}" style="color: red"></h3>
<form action="/login" method="post">
<label>账号: <input type="text" name="username" placeholder="请输入用户名"></label><br>
<label>密码: <input type="password" name="password" placeholder="请输入密码"></label><br>
<input type="submit" value="登录">
</form>
</body>
</html>

main.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>主页</title>
</head>
<body>
<a href="/logout"><button>退出登录</button></a>
<hr>
<a href="/user/list">UserList</a>
<br>
<a href="/admin/list">AdminList</a>
</body>
</html>

noAuth.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>错误页面</title>
</head>
<body>
您没有此权限!
</body>
</html>

adminList.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>AdminList</title>
</head>
<body>
AdminList 只是一个需要 admin 权限才能访问的页面
</body>
</html>

 userList.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>UserList</title>
</head>
<body>
UserList 这是一个需要登录才能访问的页面
</body>
</html>

12. 编写数据库

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;


DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `username` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',
  `password` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码',
  `prems` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

INSERT INTO `user` VALUES (1, 'lilei', '202cb962ac59075b964b07152d234b70', 'user:admin');
INSERT INTO `user` VALUES (2, 'hanmeimei', '202cb962ac59075b964b07152d234b70', 'user:user');

SET FOREIGN_KEY_CHECKS = 1;

 源码下载: springboot + shiro demo 下载地址

 

posted @ 2019-12-02 14:24  宅男大咖  阅读(1288)  评论(0编辑  收藏  举报