springboot整合shiro数据库认证

创建项目

在这里插入图片描述

1、开发数据库注册

1、开发注册界面

<h1>用户注册</h1>
<form action="/user/register" method="post">
    用户名:<input type="text" name="username" > <br/>
    密码  : <input type="text" name="password"> <br>
    <input type="submit" value="立即注册">
</form>

在这里插入图片描述

2、创建数据表结构

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
  `id` int(6) NOT NULL AUTO_INCREMENT,
  `username` varchar(40) DEFAULT NULL,
  `password` varchar(40) DEFAULT NULL,
  `salt` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

SET FOREIGN_KEY_CHECKS = 1;

在这里插入图片描述

3、项目引入依赖

<!--mybatis相关依赖-->
        <!--mybatis相关依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3.4</version>
        </dependency>
		<!--引入shiro整合springboot依赖-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.8.0</version>
        </dependency>
        <!--druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.25</version>
            <scope>runtime</scope>
        </dependency>

4、配置application.yaml配置文件

spring:
  application:
    # 应用名字
    name: shiro
  mvc:
    view:
      prefix: /
      suffix: .html
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/shirodemo?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    type: com.alibaba.druid.pool.DruidDataSource
server:
  # 端口号
  port: 8888
mybatis:
  #别名
  type-aliases-package: com.zhubayi.shirodb.entity
  #xml的位置
  mapper-locations: classpath:mapper/*Mapper.xml

5、创建entity

/**
 * @author zhubayi
 */
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class User {
    @TableId(type = IdType.AUTO)
    private String  id;
    private String username;
    private String password;
    private String salt;
}

6、创建Mapper接口

/**
 * @author zhubayi
 */
@Mapper
public interface UserMapper extends BaseMapper<User> {
	void save(User user);
}

7、开发mapper配置文件

<?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.zhubayi.shirodb.mapper.UserMapper">
    <insert id="save" parameterType="com.zhubayi.shirodb.entity.User" useGeneratedKeys="true" keyProperty="id">
        insert into t_user values(#{id},#{username},#{password},#{salt})
    </insert>
</mapper>

8、开发service接口

/**
 * @author zhubayi
 */
/**
 * @author zhubayi
 */
public interface UserService extends IService<User> {
    /**
     * 注册
     * @param user
     */
    void register(User user);
}

8、创建salt工具类

/**
 * @author zhubayi
 */
public class SaltUtils {
    /**
     * 生成salt的静态方法
     * @param n
     * @return
     */
    public static String getSalt(int n){
        char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890!@#$%^&*()".toCharArray();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < n; i++) {
            char aChar = chars[new Random().nextInt(chars.length)];
            sb.append(aChar);
        }
        return sb.toString();
    }
}

9、开发service实现类

/**
 * @author zhubayi
 */
@Service
@Transactional
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Autowired
    private UserMapper userMapper;

    /**
     * 注册
     *
     * @param user
     */
    @Override
    public void register(User user) {
        //1.生产随机盐
        String salt = SaltUtils.getSalt(8);
        //2.把随机盐保存到数据库
        user.setSalt(salt);
        //3.明文密码进行md5 + salt + hash散列
        Md5Hash md5Hash = new Md5Hash(user.getPassword(),salt,1024);
        user.setPassword(md5Hash.toHex());
        userMapper.save(user);
    }
}

10、开发Controller

/**
 * @author zhubayi
 */
@Controller
@RequestMapping("user")
public class UserController {
    @Autowired
    private UserService userService;
    @PostMapping("register")
    public String register(User user){
        System.out.println(user);
        try {
            userService.register(user);
            return "redirect:/login.html";
        }catch (Exception e){
            e.printStackTrace();
            return "redirect:/register.html";
        }
    }
}

在这里插入图片描述

11、启动项目进行注册

在这里插入图片描述
在这里插入图片描述

2、开发数据库认证

1、开发Mapper

 //根据身份信息认证的方法
    User findByUserName(@Param("username") String username);

2、开发mapper配置文件

<?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.zhubayi.shirodb.mapper.UserMapper">
    <insert id="save" parameterType="com.zhubayi.shirodb.entity.User" useGeneratedKeys="true" keyProperty="id">
        insert into t_user values(#{id},#{username},#{password},#{salt})
    </insert>

    <select id="findByUserName" parameterType="String" resultType="com.zhubayi.shirodb.entity.User">
        select id,username,password,salt from t_user
        where username = #{username}
    </select>
</mapper>

3、开发Service接口

/**
 * @author zhubayi
 */
public interface UserService extends IService<User> {
    /**
     * 注册
     * @param user
     */
    void register(User user);
    User findByUserName(String username);
}

4、开发Service实现类

 @Override
    public User findByUserName(String username) {
        return userMapper.findByUserName(username);
    }

5、发在工厂中获取bean对象的工具类

/**
 * @author zhubayi
 */
@Component
public class ApplicationContextUtils implements ApplicationContextAware {
    private static ApplicationContext context;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }
    //根据bean名字获取工厂中指定bean 对象
    public static Object getBean(String beanName){
        return context.getBean(beanName);
    }
}

6、修改自定义realm

/**
 * @author zhubayi
 */
public class MyRealm extends AuthorizingRealm {
    private UserService userService;
    public MyRealm(UserService userService){
        this.userService=userService;
    }
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    /**
     * 认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取身份信息
        String username=(String) authenticationToken.getPrincipal();
        //得到service
        //得到用户信息
        User user=userService.findByUserName(username);
        if(!ObjectUtils.isEmpty(user)){
            //返回数据库信息
            return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),
                    ByteSource.Util.bytes(user.getSalt()),this.getName());
        }
        return null;
    }
}

7、修改ShiroConfig中realm使用凭证匹配器以及hash散列

@Bean
    public Realm getRealm(UserService userService){
        MyRealm myRealm = new MyRealm(userService);
        //设置hash的凭证匹配器
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //设置md5加密
        credentialsMatcher.setHashAlgorithmName("md5");
        //设置散列次数
        credentialsMatcher.setHashIterations(1024);
        myRealm.setCredentialsMatcher(credentialsMatcher);
        return myRealm;
    }

8、开发controller并且测试

@PostMapping("login")
    public String login(String username,String password){
        //获取主体对象
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(new UsernamePasswordToken(username,password));
            return "redirect:/index.html";
        }catch (UnknownAccountException e){
            e.printStackTrace();
            System.out.println("用户名错误");
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("密码错误");
        }
        return "redirect:/login.html";
    }

在这里插入图片描述
在这里插入图片描述

登录成功~

3、授权实现

1、添加依赖

		<!-- ThymeLeaf 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
            <version>2.5.6</version>
        </dependency>
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.1.0</version>
        </dependency>

2、页面资源授权

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<h1><shiro:principal/>欢迎进入后台管理系统</h1>
<h2><a href="/user/logout">退出登录</a></h2>
    <li  shiro:hasAnyRoles="user,admin"><a href="">用户管理</a>
        <ul>
                <li shiro:hasPermission="user:add:*"><a href="">添加</a></li>
                <li shiro:hasPermission="user:delete:*"><a href="">删除</a></li>
                <li shiro:hasPermission="user:update:*"><a href="">修改</a></li>
                <li shiro:hasPermission="user:find:*"><a href="">查询</a></li>

        </ul>
    </li>
</div>
<div shiro:hasRole="admin">
    <li><a href="">商品管理</a></li>
    <li><a href="">订单管理</a></li>
    <li><a href="">物流管理</a></li>
</div>
</body>
</html>

标签说明:

  • shiro:principal // 当前用户的登录信息,用户名之类

  • shiro:guest="" // 验证是否是游客,即未认证的用户

  • shiro:user="" // 验证是否是已认证或已记住用户

  • shiro:authenticated="" // 验证是否是已认证用户,不包括已记住用户

  • shiro:notAuthenticated= “” // 未认证用户,但是 已记住用户

  • shiro:lacksRole=“admin” // 表示没有 admin 角色的用户

  • shiro:hasAllRoles=“admin, user1” // 表示需要同时拥有两种角色

  • shiro:hasAnyRoles=“admin, user1” // 表示 拥有其中一个角色即可

  • shiro:lacksPermission=“admin:delete” // 类似于 shiro:lacksRole

  • shiro:hasAllPermissions=“admin:delete, admin:edit” // 类似于 shiro:hasAllRoles

  • shiro:hasAnyPermission=“admin:delete, admin:edit” // 类似于 hasAnyRoles

加入shiro的方言配置

  • 页面标签不起作用一定要记住加入方言处理
	@Bean(name = "shiroDialect")
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }

3、代码方式授权

@RequestMapping("save")
public String save(){
  System.out.println("进入方法");
  //获取主体对象
  Subject subject = SecurityUtils.getSubject();
  //代码方式
  if (subject.hasRole("admin")) {
    System.out.println("保存订单!");
  }else{
    System.out.println("无权访问!");
  }
  //基于权限字符串
  //....
  return "redirect:/index.jsp";
}

4、方法调用授权

  • @RequiresRoles 用来基于角色进行授权
  • @RequiresPermissions 用来基于权限进行授权
@RequiresRoles(value={"admin","user"})//用来判断角色  同时具有 admin user
@RequiresPermissions("user:update:01") //用来判断权限字符串
@RequestMapping("save")
public String save(){
  System.out.println("进入方法");
  return "redirect:/index.jsp";
}

在这里插入图片描述

5、授权数据持久化

在这里插入图片描述
一共需要五张表。
sql语句:

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_pers
-- ----------------------------
DROP TABLE IF EXISTS `t_perms`;
CREATE TABLE `t_pers` (
  `id` int(6) NOT NULL AUTO_INCREMENT,
  `name` varchar(80) DEFAULT NULL,
  `url` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for t_role
-- ----------------------------
DROP TABLE IF EXISTS `t_role`;
CREATE TABLE `t_role` (
  `id` int(6) NOT NULL AUTO_INCREMENT,
  `name` varchar(60) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for t_role_perms
-- ----------------------------
DROP TABLE IF EXISTS `t_role_perms`;
CREATE TABLE `t_role_perms` (
  `id` int(6) NOT NULL,
  `roleid` int(6) DEFAULT NULL,
  `permsid` int(6) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
  `id` int(6) NOT NULL AUTO_INCREMENT,
  `username` varchar(40) DEFAULT NULL,
  `password` varchar(40) DEFAULT NULL,
  `salt` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for t_user_role
-- ----------------------------
DROP TABLE IF EXISTS `t_user_role`;
CREATE TABLE `t_user_role` (
  `id` int(6) NOT NULL,
  `userid` int(6) DEFAULT NULL,
  `roleid` int(6) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

SET FOREIGN_KEY_CHECKS = 1;

在这里插入图片描述
然后根据数据表创建实体类
Perms:

@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class Perms implements Serializable {
    @TableId(type = IdType.AUTO)
    private String id;
    private String name;
    private String url;
}

User:

@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class User {
    @TableId(type = IdType.AUTO)
    private String  id;
    private String username;
    private String password;
    private String salt;
    @TableField(exist = false)
    private List<Role> roles;
}

Role:

@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class Role implements Serializable {
    @TableId(type = IdType.AUTO)
    private String id;
    private String name;


    //定义权限的集合
    @TableField(exist = false)
    private List<Perms> perms;


}

6、创建Mapper方法

     //根据用户名查询所有角色
    User findRolesByUserName(String username);
    //根据角色id查询权限集合
    List<Perms> findPermsByRoleId(@Param("id") String id);

7、mapper实现

    <resultMap id="userMap" type="com.zhubayi.shirodb.entity.User">
        <id column="uid" property="id"/>
        <result column="username" property="username"/>
        <!--角色信息-->
        <collection property="roles" javaType="list" ofType="com.zhubayi.shirodb.entity.Role">
            <id column="id" property="id"/>
            <result column="rname" property="name"/>
        </collection>
    </resultMap>

    <select id="findRolesByUserName" parameterType="String" resultMap="userMap">
        SELECT u.id uid,u.username,r.id,r.NAME rname
        FROM t_user u
                     LEFT JOIN t_user_role ur
                ON u.id=ur.userid
                     LEFT JOIN t_role r
                ON ur.roleid=r.id
        WHERE u.username=#{username}
    </select>

    <select id="findPermsByRoleId" parameterType="String" resultType="com.zhubayi.shirodb.entity.Perms">
        SELECT p.id,p.NAME,p.url,r.NAME
        FROM t_role r
                     LEFT JOIN t_role_perms rp
                ON r.id=rp.roleid
                     LEFT JOIN t_perms p ON rp.permsid=p.id
        WHERE r.id=#{id}
    </select>

8、Service接口

	//根据用户名查询所有角色
    User findRolesByUserName(String username);
    //根据角色id查询权限集合
    List<Perms> findPermsByRoleId(String id);

8、Service实现

@Override
    public User findRolesByUserName(String username) {
        return userMapper.findRolesByUserName(username);
    }

    @Override
    public List<Perms> findPermsByRoleId(String id) {
        return userMapper.findPermsByRoleId(id);
    }

9、修改自定义realm

 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //拿到主体
        String primaryPrincipal =(String) principalCollection.getPrimaryPrincipal();
        //得到用户信息包含权限权限信息
        User user = userService.findRolesByUserName(primaryPrincipal);
        //授权信息
        if(!CollectionUtils.isEmpty(user.getRoles())){
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            user.getRoles().forEach(role -> {
                //角色信息
                simpleAuthorizationInfo.addRole(role.getName());
                //权限信息
                List<Perms> perms = userService.findPermsByRoleId(role.getId());
                // 功能列表
                Set<String> menus = new HashSet();
                if(!CollectionUtils.isEmpty(perms)){
                    for (Perms permission : perms) {
                        if(StringUtils.isNotEmpty(permission.getName())) {  //加一个非空判断
                            menus.add(permission.getName());
                        }
                    }
                    simpleAuthorizationInfo.addStringPermissions(menus);
                }
            });
            return simpleAuthorizationInfo;
        }
        return null;
    }

10、启动测试

在数据库添加数据:

用户数据:t_user

在这里插入图片描述

角色数据:t_role
**加粗样式**
用户角色关联数据:t_user_role
在这里插入图片描述
菜单权限数据:t_perms

在这里插入图片描述
角色菜单权限关联数据:t_role_perms
在这里插入图片描述
这个用户是普通用户登录之后只能看到,用户管理。
在这里插入图片描述
当再t_user_role表增加一个管理管理员角色。
在这里插入图片描述
刷新之后,就可以看到管理员所拥有的权限。
在这里插入图片描述

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值