Shiro入门

Shiro是apache旗下的一个开源安全框架,它可以帮助我们完成身 份认证,授权、加密、会话管理等功能。它有如下特点:

易于理解的API

简单的身份认证,支持多种数据源

简单的授权和鉴权

简单的加密API

支持缓存,以提升应用程序的性能

内置会话管理,适用于Web以及非Web的环境

不跟任何的框架或者容器捆绑,可以独立运行

认证

认证即系统判断用户的身份是否合法,合法可继续访问,不合法则拒绝访问。常见的用户身份认证方式有:用户名密码登录、二维码登录、手机短信登录、脸部识别认证、指纹认证等方式。认证是为了保护系统的隐私数据与资源,用户的身份合法才能访问该系统的资源。

授权

授权即认证通过后,根据用户的权限来控制用户访问资源的过程,拥有资源的访问权限则正常访问,没有权限则拒绝访问。 比如在一些视频网站中,普通用户登录后只有观看免费视频的权限,而VIP用户登录后,网站会给该用户提供观看VIP视频的权限。认证是为了保证用户身份的合法性,授权则是为了更细粒度的对隐私数据进行划分,控制不同的用户能够访问不同的资源。举个例子:认证是公司大门识别你作为员工能进入公司,而授权则是由于你作为公司会计可以进入财务室,查看账目,处理财务数据。

Shiro介绍_Shiro核心功能

Shiro入门_第1张图片

 

  • Authentication:身份认证/登录。
  • Authorization:权限验证,即判断用户是否能在系统中做某件事情。
  • Session Management:会话管理,用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中,会话可以是 JavaSE环境的,也可以是Web环境的。
  • Cryptography:加密,保护数据的安全性。即密码加密存储到数据库,而不是明文存储。
  • Web Support:Web 支持,可以非常容易的集成到Web环境。
  • Caching:缓存。在用户登录后,用户信息、拥有的权限不必每次去查,这样可以提高效率。
  • Concurrency:Shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去。
  • Testing:提供测试支持。
  • Run As:允许一个用户假装为另一个用户的身份进行访问。
  •    *   Remember Me:记住我,即一次登录后,下次再来就不用登录了。

Shiro介绍_Shiro核心组件

Shiro入门_第2张图片

 

Subject

主体。 Subject 在Shiro中是一个接口,接口中定义了认证授权的相关方法。程序通过调用 Subject 的方法进行认证授权,而 Subject 使用SecurityManager 进行认证授权。

SecurityManager

权限管理器,它是Shiro的核心。通过 SecurityManager 可以完成具体的认证、授权等操作, SecurityManager 是通过 Authenticator 进行认证,通过Authorizer 进行授权,通过 SessionManager 进行会话管理。 SecurityManager 是一个接口,继承了 Authenticator , Authorizer , SessionManager 三个接口。

Authenticator

认证器。对用户登录时进行身份认证

Authorizer

授权器。用户认证通过后,在访问功能时需要通过授权器判断用户是否有此功能的操作权限。

SessionManager

会话管理。shiro框架定义了一套会话管理,它不依赖web容器的session,所以shiro可以使用在非web应用上。

Realm

领域。他是连接数据源+认证功能+授权功能的具体实现。SecurityManager 通过 Realm 获取用户的身份和权限信息,并对用户进行认证和授权。

SessionDAO

会话dao,是对会话进行操作的一套接口。它可以将session数据存储到数据库或缓存服务器中。

CacheManager

缓存管理,将用户权限数据存储在缓存中,这样可以减少权限查询次数,提高性能。

Cryptography

密码管理,Shiro提供了一套加密/解密的组件,方便开发。

Shiro入门_项目搭建

创建springboot项目

Shiro入门_第3张图片

 依赖:



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.6.13
         
    
    com.ss.demo
    myshiro
    0.0.1-SNAPSHOT
    myshiro
    myshiro
    
        1.8
    
    
        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            mysql
            mysql-connector-java
            runtime
        
        
            org.projectlombok
            lombok
            true
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
        
            com.baomidou
            mybatis-plus-boot-starter
            3.5.0
        
        
        
            org.apache.shiro
            shiro-spring
            1.9.0
        
        
        
            org.springframework.boot
            spring-boot-starter-jdbc
        
        
        
            com.github.theborakompanioni
            thymeleaf-extras-shiro
            2.0.0
        
        
        
            org.apache.shiro
            shiro-ehcache
            1.9.0
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
                
                    
                        
                            org.projectlombok
                            lombok
                        
                    
                
            
        
    

编写配置文件:

server:
  port: 80

# 数据源
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url:  jdbc:mysql://localhost:3306/myshiro?useSSL=false
    username: root
    password: 123.com

创建包com.ss.demo.controller并创建类PageController

package com.ss.demo.controller;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class PageController {
    @RequestMapping("/{page}")
    public  String showpage(@PathVariable String page){
        return  page;
    }

    // 忽略浏览器获取项目图标
    @GetMapping("favicon.ico")
    @ResponseBody
    public void noFavicon(){}
}

拷贝页面资源:

Shiro入门_第4张图片

 然后启动测试即可,在浏览器输入http://localhost/login

Shiro入门_第5张图片

 Shiro入门_配置文件认证

Shrio支持多种数据源,我们首先将用户名密码写入配置文件,让 Shiro读取配置文件进行认证。

在 resources 目录创建配置文件 shiro.ini

#声明用户账号
[users]
admin=123

编写登录控制器方法

在包com.ss.demo.controller创建LoginController,进行认证操作【就是登陆操作】

package com.ss.demo.controller;
//登录的认证操作

import com.ss.demo.service.UsersService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.sql.DataSource;
@Controller
public class LoginController {


    @RequestMapping("/login")
    public String login(String username ,String password){
        //1.获得SecurityManager工厂,读取配置文件

        IniSecurityManagerFactory factory=new IniSecurityManagerFactory("classpath:shiro.ini");

        //2.获得SecurityManager对象
        SecurityManager securityManager= factory.getInstance();

        //3.将SecurityManager对象设置到运行环境中
        SecurityUtils.setSecurityManager(securityManager);

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

        //5.将前端传过来的用户名和密码封装为Shiro提供的身份对象
        UsernamePasswordToken token=new UsernamePasswordToken(username,password);

        try {
            //shiro认证
            subject.login(token);
            return "main";
        } catch (AuthenticationException e) {
            e.printStackTrace();
            return "fail";
        }

    }



@Autowired
private DataSource dataSource;
    /**
     * 数据库登录操作
     * @param username
     * @param password
     * @return
     */
    @RequestMapping("/user/login2")
    public String login2(String username, String password) {

        //获取SecurityManager对象
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 2.为SecurityManager对象设置Realm
        JdbcRealm jdbcRealm = new JdbcRealm();
        jdbcRealm.setDataSource(dataSource);
        securityManager.setRealm(jdbcRealm);
        // 3.将SecurityManager对象设置到运行环境中
        SecurityUtils.setSecurityManager(securityManager);
        // 4.获取Subject对象
        Subject subject = SecurityUtils.getSubject();
        // 5.将前端传来的用户名密码封装为Shiro提供的身份对象
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        System.out.println(token);

        try {
            //认证操作
            subject.login(token);
            //跳转到主页面
            return "main";
        } catch (AuthenticationException e) {
            e.printStackTrace();
            return "fail";
        }

    }
}

启动项目,访问登录页http://localhost/login,测试登录功能。

输入用户名和密码:

Shiro入门_第6张图片

 

跳转到:

 如果输入错误就会跳转到失败页面

Shiro入门_数据库认证

之前我们使用配置文件做数据源,在真实开发中,我们往往会使用 数据库作为数据源进行认证操作。 Realm 负责连接数据源并进行具体 认证,它有一个子类 JdbcRealm ,该类可以自动连接数据库认证。

创建数据库myshiro:

创建数据表 users

CREATE TABLE `users`  (
  `username` VARCHAR(255) DEFAULT NULL,
  `password` VARCHAR(255) DEFAULT NULL
) ENGINE = INNODB CHARACTER SET = utf8;

INSERT INTO `users` VALUES ('admin','123');

在包com.ss.demo.controller创建LoginController 编写登录控制器方法【数据库】

@Autowired
private DataSource dataSource;

/**
 * 数据库登录操作
 * @param username
 * @param password
 * @return
 */
@RequestMapping("/user/login2")
public String login2(String username, String password) {
    //获取SecurityManager对象
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    // 2.为SecurityManager对象设置Realm
    JdbcRealm jdbcRealm = new JdbcRealm();
    jdbcRealm.setDataSource(dataSource);
    securityManager.setRealm(jdbcRealm);
    // 3.将SecurityManager对象设置到运行环境中
    SecurityUtils.setSecurityManager(securityManager);
    // 4.获取Subject对象
    Subject subject = SecurityUtils.getSubject();
    // 5.将前端传来的用户名密码封装为Shiro提供的身份对象
    UsernamePasswordToken token = new UsernamePasswordToken(username, password);
    System.out.println(token);

    try {
        //认证操作
        subject.login(token);
        //跳转到主页面
        return "main";
    } catch (AuthenticationException e) {
        e.printStackTrace();
        return "fail";
    }
}

启动项目,访问登录页http://localhost/login,测试登录功能。

输入用户名和密码即可跳转

 

Shiro认证_将Shiro对象交给容器管理

之前的案例中,所有关于Shiro的对象都是自己创建的。我们在 SpringBoot中使用Shiro,就可以将Shiro的对象交给容器管理,简化业务代码。

创建Shiro配置类

在项目myshiro中创建包com.ss.demo.config,并创建配置类ShiroConfig

package com.ss.demo.config;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@Configuration
public class ShiroConfig {
    //获取SecurityManager对象
    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager(JdbcRealm jdbcRealm) {
        DefaultWebSecurityManager defaultSecurityManager=new DefaultWebSecurityManager();
        defaultSecurityManager.setRealm(jdbcRealm);
        return defaultSecurityManager;
    }
    @Bean
    public JdbcRealm jdbcRealm(DataSource dataSource) {
        JdbcRealm jdbcRealm = new JdbcRealm();
        jdbcRealm.setDataSource(dataSource);
        return jdbcRealm;
    }
}

在项目myshiro中创建包com.ss.demo.service,并创建类UsersService;

package com.ss.demo.service;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 用户service
 */
@Service
public class UsersService {

    @Autowired
    private DefaultWebSecurityManager securityManager;

    public void userLogin(String username, String password) {
        // 1.将SecurityManager对象设置到运行环境中
        SecurityUtils.setSecurityManager(securityManager);
        // 2.获取Subject对象
        Subject subject = SecurityUtils.getSubject();
        // 3.将前端传来的用户名密码封装为Shiro提供的身份对象
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
        // 4.Shiro认证
        subject.login(token);
    }
}

在包com.ss.demo.controller创建LoginController 编写登录控制器方法

 

@Autowired
private UsersService usersService;

/**
 * 数据库登录操作
 * @param username
 * @param password
 * @return
 */
@RequestMapping("/user/login3")
public String login3(String username, String password) {
    try {
        usersService.userLogin(username,password);
        return "main";
    } catch (Exception e) {
        e.printStackTrace();
        return "fail";
    }
}

Shiro认证_自定义Realm

使用 JdbcRealm 认证时,数据库表名、字段名、认证逻辑都不能改变, 我们可以自定义Realm进行更灵活的认证。

修改数据库users:

CREATE TABLE `users`  (
  `uid` INT(11) NOT NULL AUTO_INCREMENT,
  `username` VARCHAR(255)  DEFAULT NULL,
  `password` VARCHAR(255)   DEFAULT NULL,
  PRIMARY KEY (`uid`) 
) ENGINE = INNODB CHARACTER SET = utf8;
 
INSERT INTO `users` VALUES (1, 'admin', '123');

编写实体类

在项目中创建包com.ss.demo.entity,并创建实体类Users

package com.ss.demo.entity;

import lombok.Data;

@Data
public class Users {
    private Integer uid;
    private String username;
    private String password;
}

编写mapper接口在包com.ss.demo.mapper中新建UsersMapper

package com.ss.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ss.demo.domain.Users;
/**
 * Mapper接口
 */
public interface UsersMapper extends BaseMapper {

}

主启动类扫描Mapper

package com.ss.demo;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@MapperScan("com.ss.demo.mapper")
@SpringBootApplication
public class MyshiroApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyshiroApplication.class, args);
    }
}

自定义realm

新建包com.ss.demo.realm并新建类MyRealm

package com.ss.demo.realm;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ss.demo.mapper.UsersMapper;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * 自定义realm
 */
public class MyRealm extends AuthorizingRealm {
    //自定义授权方法
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {


        return null;
    }

    //自定义认证方法
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        return null;
    }
}

进行认证操作:

package com.ss.demo.realm;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ss.demo.domain.Users;
import com.ss.demo.mapper.UsersMapper;
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.springframework.beans.factory.annotation.Autowired;
/**
 * 自定义realm
 */
public class MyRealm extends AuthorizingRealm {
    @Autowired
    private UsersMapper usersMapper;
    //自定义授权方法
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {


        return null;
    }

    //自定义认证方法
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取用户输入的用户名
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username = token.getUsername();

        //根据用户查询用户信息
        QueryWrapper wrapper = new QueryWrapper<>();
        wrapper.eq("username", username);
        Users users = usersMapper.selectOne(wrapper);

        //将查询到的管理员封装为认证信息
        if(users == null) {
            throw new UnknownAccountException("用户不存在");
        }
        //参数1查询的用户信息
        //参数2查询的用户密码
        //参数3Realm名称
        return new SimpleAuthenticationInfo(users, users.getPassword(),"myRealm");
    }
}

然后我们回到包com.pb.ss.config的配置类中ShiroConfig把JdbcRealm注释掉,使用我们自定义的MyRealm

package com.ss.demo.config;


import com.ss.demo.realm.MyRealm;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;

@Configuration
public class ShiroConfig {
    //获取SecurityManager对象
   /* @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager(JdbcRealm jdbcRealm) {
        DefaultWebSecurityManager defaultSecurityManager=new DefaultWebSecurityManager();
        defaultSecurityManager.setRealm(jdbcRealm);
        return defaultSecurityManager;
    }*/
   /* @Bean
    public JdbcRealm jdbcRealm(DataSource dataSource) {
        JdbcRealm jdbcRealm = new JdbcRealm();
        jdbcRealm.setDataSource(dataSource);
        return jdbcRealm;
    }*/


    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager(MyRealm myRealm){
        DefaultWebSecurityManager defaultWebSecurityManager=new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(myRealm);
        return defaultWebSecurityManager;
    }
    @Bean
    public MyRealm myRealm(){
        MyRealm myRealm=new MyRealm();
        return myRealm;
    }
}

启动测试

你可能感兴趣的:(java)