springboot + shiro 实现认证授权(快速上手详细教程)

本篇主要讲述springboot搭建以及利用shiro实现认证授权,没有过多关于shiro框架基础信息的描述,只是注重shiro使用详细步骤介绍。

目录

一、springboot项目的搭建

        a:file -> new -> project

二、 shiro框架的搭建

        a:引入依赖并添加配置

        b:创建数据库表

                1.用户表(认证先只创建这一个)

:​

               2.用户表简单CRUD操作:

        c:shiro核心类的配置

              1.密码匹配器的配置:


一、springboot项目的搭建

        a:file -> new -> project

 

至此一个简单的springboot项目创建完毕,最终形式如下图:


二、 shiro框架的搭建

        a:引入依赖并添加配置

        <!-- shiro 安全框架-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-all</artifactId>
            <version>1.5.3</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.6</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-redis</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>
        <!--工具类包-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 分页插件 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.3.1</version>
        </dependency>

       application.yml配置:

#port
server:
  port: 1234

spring:
  ####### database Config #######
  datasource:
    url: jdbc:mysql://localhost:3306/myshiro?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false&allowPublicKeyRetrieval=true&useLegacyDatetimeCode=false
    username: root
    password: zy169693
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver

  ####### Redis Config #######
  redis:
    host: 127.0.0.1
    port: 6379
    password: root
    # 连接超时时间(毫秒)
    timeout: 5000ms
    # 默认的数据过期时间,主要用于shiro权限管理
    expire: 2592000
    jedis:
      pool:
        # 连接池最大连接数(使用负值表示没有限制)
        max-active: 8
        # 连接池最大阻塞等待时间(使用负值表示没有限制)
        max-wait: -1ms
        # 连接池中的最大空闲连接
        max-idle: 8
        # 连接池中的最小空闲连接
        min-idle: 0

  ####### redis缓存服务配置 #######
  session:
    store-type: redis
  jpa:
    open-in-view: false

####### mybatis-plus #######
mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true
    auto-mapping-behavior: full
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath:mapper/*.xml

 


  

        b:创建数据库表

                1.用户表(认证先只创建这一个):

CREATE TABLE `sys_user` (
  `user_id` int NOT NULL AUTO_INCREMENT COMMENT '用户id',
  `user_name` varchar(255) NOT NULL COMMENT '用户名',
  `nick_name` varchar(255) DEFAULT NULL,
  `passwd` varchar(255) NOT NULL COMMENT '密码',
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

               2.用户表简单CRUD操作:

package priv.ian.demo.controller;

import cn.hutool.core.util.ObjectUtil;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import priv.ian.demo.common.Response;
import priv.ian.demo.entity.User;
import priv.ian.demo.service.SysUserService;
import priv.ian.demo.vo.UserConditionVO;

import javax.annotation.Resource;
import java.util.List;

/**
 * 用户管理
 *
 * @author ian zhao
 * @since 2021-10-04 20:27:05
 */
@Slf4j
@RestController
@RequestMapping("/sysUser")
public class RestUserController {
    /**
     * 服务对象
     */
    @Resource
    private  SysUserService sysUserService;

    /**
     * 通过主键查询单条数据
     *
     * @param user 参数对象
     * @return 单条数据
     */
    @RequestMapping(value = "get", method = RequestMethod.GET)
    public Response<User> selectOne(User user) {
        User result = sysUserService.selectById(user.getId());
        if (result != null) {
            return Response.createSuccessResponse("查询成功", result);
        }
        return Response.createErrorResponse("查询失败");
    }

    /**
     * 新增一条数据
     *
     * @param user 实体类
     * @return Response对象
     */
    @RequestMapping(value = "insert", method = RequestMethod.POST)
    public Response<User> insert(User user) {
        if (ObjectUtil.isEmpty(user)) {
            return Response.createErrorResponse("用户为空,添加失败!");
        }
        try {
            int result = sysUserService.insert(user);
            if (result > 0) {
                return Response.createSuccessResponse("新增成功", user);
            }
        } catch (Exception e) {
            log.error("failed to insert ",e);
        }
        return Response.createErrorResponse("新增失败");
    }

    /**
     * 用户修改
     * @param user user
     * @return response
     */
    @RequestMapping(value = "update", method = RequestMethod.PUT)
    public Response<User> update(@RequestBody User user) {
        if (ObjectUtil.isEmpty(user)) {
            return Response.createErrorResponse("用户为空,修改失败!");
        }
        int result = sysUserService.update(user);
        if (result > 0) {
            return Response.createSuccessResponse("修改成功", user);
        }
        return Response.createErrorResponse("修改失败");
    }

    /**
     * 删除一条数据
     *
     * @param ids ids
     * @return Response对象
     */
    @RequestMapping(value = "delete", method = RequestMethod.DELETE)
    public Response<User> delete(List<Long> ids) {
        int result = sysUserService.deleteById(ids);
        if (result > 0) {
            return Response.createSuccessResponse("删除成功", null);
        }
        return Response.createErrorResponse("删除失败");
    }

    /**
     * 查询全部
     *
     * @return Response对象
     */
    @RequestMapping(value = "selectAll", method = RequestMethod.GET)
    public Response<List<User>> selectAll() {
        List<User> sysUsers = sysUserService.selectAll();
        if (sysUsers != null) {
            return Response.createSuccessResponse("查询成功", sysUsers);
        }
        return Response.createErrorResponse("查询失败");
    }

    /**
     * 分页查询
     *
     * @param vo vo
     * @return Response对象
     */
    @RequestMapping(value = "selectPage", method = RequestMethod.GET)
    public Response<PageInfo<User>> selectPage(UserConditionVO vo) {
        PageInfo<User> users = sysUserService.selectPage(vo);
        if (users != null) {
            return Response.createSuccessResponse("查询成功", users);
        }
        return Response.createErrorResponse("查询失败");
    }
}

        c:shiro核心类的配置

                shiro的核心类包括三大块(securityManager、subject、realm)以及密码匹配器(matcher),接下来依次展示。

              1.密码匹配器的配置(验证密码):

        

package priv.ian.demo.shiro.credentials;

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import priv.ian.demo.util.PasswdUtil;

/**
 * @Description shiro-密码凭证匹配器(验证密码)
 * @Author: Ian
 * @Date: 2021/10/3 8:09 下午
 * @Version: ${1.0}
 */
public class CredentialsMatcher extends SimpleCredentialsMatcher {

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        UsernamePasswordToken userToken = (UsernamePasswordToken) token;
        //输入框的密码
        String inPasswd = String.valueOf(userToken.getPassword());

        //数据库中的加密密码
        String dbPasswd = (String) info.getCredentials();

        try {
            dbPasswd = PasswdUtil.decrypt(userToken.getUsername(),dbPasswd);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

        //密码校验
        return this.equals(inPasswd,dbPasswd);
    }
}

                2.认证授权的配置(与数据库交互)

package priv.ian.demo.shiro.realm;

import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import priv.ian.demo.entity.User;
import priv.ian.demo.service.SysUserService;

import javax.annotation.Resource;

/**
 * @Description shiro - 密码输入错误的状态下重试次数的匹配管理
 * @Author: Ian
 * @Date: 2021/10/9 11:45 下午
 * @Version: ${1.0}
 */
public class ShiroRealm extends AuthorizingRealm {

    @Resource
    private SysUserService userService;


    /**
     * 认证
     *
     * @param token token
     * @return info
     * @throws AuthenticationException e
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //获取用户的输入账号
        String username = (String) token.getPrincipal();
        User user = userService.selectByUserName(username);
        if (user == null) {
            throw new UnknownAccountException("账号不存在!");
        }

        //principal 参数使用userId ,方便动态刷新用户权限
        return new SimpleAuthenticationInfo(
                user.getId(),
                user.getPassword(),
                ByteSource.Util.bytes(username),
                getName()
        );
    }


    /**
     * 授权
     *
     * @param principalCollection s
     * @return info
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

}

                3. securityManager配置(shiroConfig-核心配置)

        


版权声明:本文为Ian_1216原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。