自学内容网 自学内容网

Shiro认证(Authentication)

目录

1.1 Shiro简介

1.1.1 Shiro特性 

 Shiro的特点

1.1.2 Shiro架构

1.2 认证(Authentication)

1.2.1 快速上手

添加依赖

 配置shiro.ini

 认证测试

 运行结果

1.2.2 认证流程

1.3 SpringBoot+Shiro认证

1.3.1 基础代码调整

1.3.2 自定义Reaml

1.3.3 配置Shiro相关对象

 1.3.4 Controller层重写登陆方法


1.1 Shiro简介

        Apache Shiro是一个强大易用的Java安全框架,提供了认证、授权、会话管理和加密等功能。对于任意一个应用程序,Shiro都可以提供全面的安全管理服务,对比Spring Security,可能没有Spring Security功能强大,但是完美在实际工作中可能不需要那么复杂的功能,所以使用简单易用的Shiro就已经足够了。

1.1.1 Shiro特性 

 Shiro的特点
  1. 易于理解的API 简单的身份认证,支持多种数据源
  2. 简单的授权和鉴权
  3. 简单的加密API
  4. 支持缓存,以提升应用程序的性能
  5. 内置会话管理,适用于Web以及非Web的环境
  6. 不跟任何的框架或者容器捆绑,可以独立运行

Authentication(认证),Authorization(授权),Session Management(会话管理),Cryptography(加密)被Shiro框架的开发团队称之为应用安全的四大基石

Authentication:身份认证/登录。

  • Authorization:权限验证,即判断用户是否能在系统中做某件 事情。

  • Session Management:会话管理,用户登录后就是一次会 话,在没有退出之前,它的所有信息都在会话中,会话可以是 JavaSE环境的,也可以是Web环境的。

  • Cryptography:加密,保护数据的安全性。即密码加密存储到 数据库,而不是明文存储。 Web Support:Web 支持,可以非常容易的集成到Web环境。 

  • Caching:缓存。在用户登录后,用户信息、拥有的权限不必每 次去查,这样可以提高效率。

  • Concurrency:Shiro支持多线程应用的并发验证,即如在一个 线程中开启另一个线程,能把权限自动传播过去。

  • Testing:提供测试支持。

  • Run As:允许一个用户假装为另一个用户的身份进行访问。

  • Remember Me:记住我,即一次登录后,下次再来就不用登 录了。

1.1.2 Shiro架构

 从应用程序的角度来看如何使用Shir完成工作。

如下图:

 可以看到应用代码直接交互的对象是Shuject,也就是说Shiro的对外API核心就是Subject;其每个API的含义如下:

  • Subject:主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都能是Subject,如网络爬虫,机器人等,即一个抽象概念。所有Subject都绑定到SecurityManager,与Subject的所有交互都是委托给SecurityManager。

  • SecurityManager:安全管理器,即所有与安全有关的操作都会与SecurityManager交互,且它管理着所有Subject;可以看出它是Shiro的核心,它负责与后边介绍的其他组件进行交互。

  • Realm:域,Shiro从Realm对象获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证是否能进行操作;可以把Realm看成DataSource,即安全数据源。

接下来完美从Siro内部来看下Shiro的架构。

如下图:

  •  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提供了一套加密/解密的组件,方便开发。

1.2 认证(Authentication)

        在Shiro中,认证指的是识别和证明操作者是一个合法用户。

1.2.1 快速上手

添加依赖
        <!-- 引入shiro -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>2.0.1</version>
        </dependency>
        <!-- 引入Java-API-->
        <!-- 因为Spring Boot3.3.4版本更新的原因原有的API的位置改变了所以需要引入Java-API,原来是不用引入的 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
 配置shiro.ini

在resoureces目录下新建shiro.ini文件配置用户认证数据

[users]
#用户账号和密码
#配置规则:用户账号=密码
admin = 123456
czkt = 111111
 认证测试
public class ShiroTester {

    @Test
    public void testShiro() {
        // 通过shiro.ini配置文件创建realm
        IniRealm realm = new IniRealm("classpath:shiro.ini");
        // 配置SerurityManager
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        // 注入创建的realm
        securityManager.setRealm(realm);
        SecurityUtils.setSecurityManager(securityManager);
        // 操作Subject,进行认证
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456");
        try{
            subject.login(token);
        }catch (Exception e) {
            System.out.println("认证异常:");
            e.printStackTrace();
        }
        System.out.println("是否认证成功:" + subject.isAuthenticated());
        System.out.println("身份信息:" + subject.getPrincipal());

    }
}
 运行结果
是否认证成功:true
身份信息:admin

1.2.2 认证流程

        通过前面的测试用例,我们只看到如何在程序代码中验证一个Subject,现在我们看一下当一个验证发生是Shiro内部发生了什么。

流程如下:

  1. 首先调用 Subject.login(Token) 进行登录,其会自动委托给 Security Manager,调用之前通过 SecurityUtils.setSecurityManager()设置Security Manager;
  2. SecurityManager 负责真正的身份验证逻辑,他会委托给 Authenticator 进行身份验证;
  3. Authentication 才是真正的身份验证者,Shiro API 中核心的身份认证入口点,此处可以自定义插入自己的实现。
  4. Authenticator 可能会委托给相应的 AuthenticationStrategy 进行多 Realm 身份验证,默认 ModularRealmAuthenticator 会调用 AuthenticationStrategy 进行多 Realm 身份验证。
  5. Authenticator 会把相应的Token 传入 Realm,从Realm获取身份信息,如果没有返回 / 抛出异常表示身份验证失败了,此处可以配置多个 Realm,将按照相应的顺序及策略进行访问。

1.3 SpringBoot+Shiro认证

        SpringBoot+Shiro实现动态认证,Shiro只要做两件事即可:1、自定义Realm;2、配置Shiro相关对象

1.3.1 基础代码调整

UserMapper新增findUserByUsrName方法

User findUserByUsrName(String usrName);

 根据用户名查询用户对象,密码(凭证)是否正确由后续Shiro在认证时判断。

UserService接口新增findUserByUsrName方法和在UserServiceImpl实现类中实现

1.3.2 自定义Reaml

public class MyShiroRealm extends AuthorizingRealm {
    @Resource
    private UserService userService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) throws AuthenticationException{
        System.out.println("调用MyShiroRealm.doGetAuthorizationInfo获取权限信息!");
        User user = (User) principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("调用MyShiroRealm.doGetAuthenticationInfo获取身份信息!");
        // 获得身份信息
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String usrName = token.getUsername();
        User user = userService.findUserByUsrName(usrName);
        if(user == null){
            throw new UnknownAccountException(); // 账号错误
        }
        if(user.getUsrFlag() == null || user.getUsrFlag().intValue() == 0){
            throw new LockedAccountException(); // 账号被锁定
        }
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getUsrPassword(),getName());
        return info;
    }

}

1.3.3 配置Shiro相关对象

@Configuration
public class ShiroConfig {

    @Bean
    public MyShiroRealm myShiroRealm() {
        MyShiroRealm shiroRealm = new MyShiroRealm();
        return shiroRealm;
    }

    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        // 在注册bean的时候,加入下面这句话,将securityManager放到SecurityUtils里面
        SecurityUtils.setSecurityManager(securityManager);
        return securityManager;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactory(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactory = new ShiroFilterFactoryBean();
        shiroFilterFactory.setSecurityManager(securityManager);
        return shiroFilterFactory;
    }

}

 1.3.4 Controller层重写登陆方法

    @PostMapping("/doLogin")
    public String doLogin(String usrName, String usrPassword, Model model, HttpSession session) {
        try {
            UsernamePasswordToken token = new UsernamePasswordToken(usrName, usrPassword);
            Subject subject = SecurityUtils.getSubject();
            subject.login(token); // 认证、登录
            User user = (User) subject.getPrincipal();
            session.setAttribute("loginUser", user);
            return "redirect:/main";
        }catch (UnknownAccountException | IncorrectCredentialsException e) {
            model.addAttribute("msg", "用户名或密码错误,登录失败!");
            return "login";
        }catch (LockedAccountException e) {
            model.addAttribute("msg", "账号被锁定,登录失败!");
            return "login";
        }catch (AuthenticationException e) {
            model.addAttribute("msg", "登录失败!");
            return "login";
        }
    }
    
    @GetMapping("/logout")
    public String logOut(HttpSession session) {
        session.removeAttribute("loginUser");
        session.invalidate();
        return "/login";
    }


原文地址:https://blog.csdn.net/Bisikl/article/details/142957157

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!