⑤【Shiro】SpringBoot整合Shiro,实现登录认证-LMLPHP


目录结构

目录结构




Maven坐标导入

pom.xml:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-web-starter</artifactId>
            <version>1.9.0</version>
        </dependency>
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>



准备用于登录校验的数据

创建表结构,插入数据

CREATE DATABASE IF NOT EXISTS `shirodb` CHARACTER SET utf8mb4;
USE `shirodb`;
CREATE TABLE `user` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
`name` VARCHAR(30) DEFAULT NULL COMMENT '用户名',
`pwd` VARCHAR(50) DEFAULT NULL COMMENT '密码',
`rid` BIGINT(20) DEFAULT NULL COMMENT '角色编号',
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='用户表';

# e8e2ea5deb7e981462ab88c2b7e3f19a 是123456789经过MD5加盐三次机密后的结构,加的盐为"salt"
insert into user values(1, '.29.', 'e8e2ea5deb7e981462ab88c2b7e3f19a', 1);



数据库表对应的实体类

User

/**
 * @author .29.
 * @create 2024-03-17 10:53
 */
//lombok组件注解,提供构造器以及Getter、Setter
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Integer id;
    private String name;
    private String pwd;
    private Integer rid;
}



SpringBoot配置文件

applicaition.yml:

# mybatis-plus配置
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath:mapper/*.xml
spring:
  # 数据库连接配置
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/shirodb?characterEncoding=utf-8&useSSL=false
    username: root
    password: abc123
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8



MyBatis-Plus操作数据库的Mapper接口

UserMapper:

/**
 * @author .29.
 * @create 2024-03-17 10:55
 @Repository注解用于标识一个类作为数据访问层(DAO)的组件,类似于@Component,但可以将底层数据访问技术(如 JDBC、Hibernate 等)所抛出的异常转换为 Spring 的数据访问异常(DataAccessException),这样在上层代码中可以统一处理数据访问异常。
 */
@Repository
public interface UserMapper extends BaseMapper<User> {
}




Service层,提供一个根据name查询用户的业务方法

Service接口

/**
 * @author .29.
 * @create 2024-03-17 10:56
 */
public interface UserService {
    //用户登录
    User getUserInfoByName(String name);
}

Service实现类

/**
 * @author .29.
 * @create 2024-03-17 10:57
 */
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    /**
     * 根据name查询用户的业务方法
     * @param name
     * @return
     */
    @Override
    public User getUserInfoByName(String name) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", name);
        User user = userMapper.selectOne(queryWrapper);
        return user;
    }
}



自定义Realm,实现自定义登录认证

MyRealm:

/**
 * @author .29.
 * @create 2024-03-17 11:01
 */
@Configuration
public class MyRealm extends AuthorizingRealm {//自定义Realm需要继承AuthorizingRealm
    @Autowired
    private UserService userService;

    /**
     * 自定义授权方法,这里暂时不需要设置,直接返回null
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    /**
     * 自定义登录认证方法
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //从token中获取用户身份信息
        String name = authenticationToken.getPrincipal().toString();
        //查询数据库中的用户信息
        User user = userService.getUserInfoByName(name);
        //判断并将数据封装进进行登录认证的对象,进行返回
        if(user != null && name.equals(user.getName())){
            //创建实现了校验逻辑的对象,传入校验数据,交给shiro底层进行认证
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(
                    authenticationToken.getPrincipal()
                    , user.getPwd()
                    , ByteSource.Util.bytes("salt")
                    , name
            );
            return info;
        }
        return null;
    }
}




控制层,使用Shiro进行登录认证

myController:

/**
 * @author .29.
 * @create 2024-03-17 11:27
 */
@Controller
@RequestMapping("/myController")
public class MyController {

    @GetMapping("/userLogin")
    @ResponseBody
    public String userLogin(String name, String pwd){
        //获取subject对象
        Subject subject = SecurityUtils.getSubject();
        //封装请求数据至token
        UsernamePasswordToken token = new UsernamePasswordToken(name, pwd);
        //调用login方法进行登录认证
        try{
            subject.login(token);
            System.out.println("登陆成功!");
            return "登陆成功";
        }catch (AuthenticationException e){
            e.printStackTrace();
            System.out.println("登陆失败!");
            return "登陆失败";
        }
    }
}




Shiro配置类,使自定义Realm生效,设置拦截范围

ShiroConfig

/**
 * @author .29.
 * @create 2024-03-17 11:14
 */
@Configuration
public class ShiroConfig {
    @Autowired
    private MyRealm myRealm;

    //配置SecurityManager
    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager(){
        //创建DefaultWebSecurityManager对象(安全管理器)
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        //创建加密对象,设置属性
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("MD5"); //使用什么加密算法?
        hashedCredentialsMatcher.setHashIterations(3);        //循环加密几次?
        myRealm.setCredentialsMatcher(hashedCredentialsMatcher); //为自定义Realm设置加密对象
        defaultWebSecurityManager.setRealm(myRealm);             //将自定义Realm存入安全管理器
        return defaultWebSecurityManager; //返回安全管理器
    }

    //配置Shiro内置过滤器拦截范围
    @Bean
    public DefaultShiroFilterChainDefinition defaultShiroFilterChainDefinition(){
        //创建拦截器定义对象
        DefaultShiroFilterChainDefinition filter = new DefaultShiroFilterChainDefinition();

        //配置不认证也能访问的资源(参数anon代表无需认证)
        filter.addPathDefinition("/myController/userLogin","anon");
        filter.addPathDefinition("/login","anon");
        //配置需要认证访问的资源(参数authc代表需要认证)
        filter.addPathDefinition("/**","authc");

        return filter;
    }



测试登录认证功能

启动项目,访问地址传递参数





⑤【Shiro】SpringBoot整合Shiro,实现登录认证-LMLPHP

04-19 11:21