shiro入门demo(一)身份验证

2023-12-14 18:28:35

? shiro(身份)认证,简单来说就是登录/退出。搭建springboot项目,引入shiro和单元测试依赖:

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

        <!--单元测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--shiro-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.2.2</version>
        </dependency>
    </dependencies>

身份认证的步骤:

(1)收集用户身份 / 凭证,即如用户名 / 密码;
(2)调用 Subject.login 进行登录,其会自动委托给 SecurityManager.login 方法进行登录。如果失败将得到相应的 AuthenticationException 异常,根据异常提示用户错误信息;否则登录成功。如果身份验证失败捕获 AuthenticationException 或其子类,常见的如: DisabledAccountException(禁用的帐号)、LockedAccountException(锁定的帐号)、UnknownAccountException(错误的帐号)、ExcessiveAttemptsException(登录失败次数过多)、IncorrectCredentialsException (错误的凭证)、ExpiredCredentialsException(过期的凭证)等,具体请查看其继承关系;对于页面的错误消息展示,最好使用如 “用户名 / 密码错误” 而不是 “用户名错误”/“密码错误”,防止一些恶意用户非法扫描帐号库;
(3)最后调用 Subject.logout 进行退出操作,其会自动委托给 SecurityManager.logout 方法退出。

注意:身份验证是基础,如果身份验证出错其他的都会认证失败,比如密码错误而角色、权限是正确的,角色、权限认证也会失败。

一、身份认证配置文件mock数据实现:

?1、数据mock:新建shiro-user.ini文件

[users]
zs=123
ls=123
admin=123

? 2、单元测试:

import com.demo.shiro.ShiroApplication;
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.subject.Subject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * 身份验证
 */
@SpringBootTest(classes = {ShiroApplication.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@RunWith(SpringRunner.class)
public class ShiroLoginTest{

    /**
     *登陆/退出,以admin/123用户为例
     */
    @Test
    public void testLoginInAndPut(){
        //1、创建SecurityManagerFactory,用户名/密码硬编码在ini文件,实际应存储在数据库并将密码加密
        IniSecurityManagerFactory factory=new IniSecurityManagerFactory("classpath:shiro-user.ini");
        //2、创建安全管理器SecurityManager,并绑定给SecurityUtil
        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);
        //3、通过SecurityUtil获取登入用户主体subject,并创建token
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token=new UsernamePasswordToken(
                "admin", "123"
        );
        //用户认证(shrio的核心功能之一)
        try {
            //异常
            //4、登录,即身份验证
            subject.login(token);
            System.out.println("认证成功");
        } catch (AuthenticationException e) {
            //5、认证失败
            //org.apache.shiro.authc.UnknownAccountException:账号错误异常
            //org.apache.shiro.authc.IncorrectCredentialsException:密码错误异常
            //org.apache.shiro.authz.UnauthorizedException: 授权错误异常
            System.out.println("认证失败");
            e.printStackTrace();
        }
        //6、安全退出
        subject.logout();
    }
}

执行,控制台输出:认证成功;

将密码改为123456,抛出密码错误异常

二、Realm域实现:

1、简单认证:realm一般是继承AuthorizingRealm,因为这里只有认证,就使用最简单的Realm了

package com.demo.shiro.realm;

import org.apache.shiro.authc.*;
import org.apache.shiro.realm.Realm;

public class MyRealm1 implements Realm {
    @Override
    public String getName() {
        return "myRealm1";
    }

    @Override
    public boolean supports(AuthenticationToken token) {
        //仅支持UsernamePasswordToken类型的token
        return token instanceof UsernamePasswordToken;
    }

    @Override
    public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String) token.getPrincipal();
        String password = new String((char[]) token.getCredentials());
        if(!"admin".equals(username)){
            throw new UnknownAccountException();
        }
        if(!"123".equals(password)){
            throw new IncorrectCredentialsException();
        }
        //身份验证成功,返回一个AuthenticationInfo实现
        return new SimpleAuthenticationInfo(username,password,getName());
    }
}

按照这个方法再定义MyRealm2、MyRealm3,分别实现zs/123、ls/123。注入Reaml方法有两种,

(1)配置文件方法:新建shiro-user-realm.ini文件,

#1、声明realm
myRealm1 = com.demo.shiro.realm.MyRealm1
myRealm2 = com.demo.shiro.realm.MyRealm2
myRealm3 = com.demo.shiro.realm.MyRealm3
#2、指定securityManager的realms实现
securityManager.realms = $myRealm1,$myRealm2,$myRealm3

?将单元测试原来加载的shiro-user.ini改为shiro-user-realm.ini即可。

(2)编程方法:修改单元测试代码:

 //方法1,配置文件注入realm
        //1、创建SecurityManagerFactory,用户名/密码硬编码在ini文件,实际应存储在数据库并将密码加密
        //IniSecurityManagerFactory factory=new IniSecurityManagerFactory("classpath:shiro-user-realm.ini");
        //2、创建安全管理器SecurityManager,并绑定给SecurityUtil
        //SecurityManager securityManager = factory.getInstance();

        //方法2,编程设置realm
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        List<Realm> realms = new ArrayList<>();
        realms.add(new MyRealm1());
        realms.add(new MyRealm2());
        realms.add(new MyRealm3());
        securityManager.setRealms(realms);

2、

文章来源:https://blog.csdn.net/w_t_y_y/article/details/134931758
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。