springboot整合shiro多验证登录功能的实现(账号密码登录和使用手机验证码登录)

yizhihongxing

SpringBoot整合Shiro多验证登录功能的实现

SpringBoot是一个快速开发Spring应用的框架,而Shiro可以方便的实现安全认证和授权,两者结合,可以非常方便的实现多验证登录功能。

SpringBoot集成Shiro

首先需要添加Shiro和SpringBoot的依赖。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.7.1</version>
</dependency>

然后需要配置Shiro的SpringBoot启动类,添加@Configuration注解,并添加@Bean注解的ShiroFilterFactoryBean和DefaultWebSecurityManager。

@Configuration
public class ShiroConfiguration {
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        ...
        return shiroFilterFactoryBean;
    }

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

    @Bean
    public MyRealm myRealm() {
        return new MyRealm();
    }
}

自定义Realm

接着需要自定义Realm,实现doGetAuthenticationInfo和doGetAuthorizationInfo方法。

public class MyRealm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //授权方法
        return null;
    }

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

账号密码登录验证

对于账号密码登录验证,可以通过用户名和密码进行登录认证,实现doGetAuthenticationInfo方法。

@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
    String username = token.getUsername();
    String password = new String(token.getPassword());

    //根据用户名和密码查询用户信息,可以通过MyBatis进行数据库操作
    User user = userService.findByUsernameAndPassword(username, password);
    if (user == null) {
        throw new UnknownAccountException("用户名或密码错误");
    }

    return new SimpleAuthenticationInfo(username, password, getName());
}

关于User实体和UserService可以通过自己的业务逻辑进行实现。

手机验证码登录验证

对于手机验证码登录验证,则需要在认证方法中自定义Token,用来存储手机号和验证码的信息。

public class SmsToken implements AuthenticationToken {
    private String phone;
    private String code;

    public SmsToken(String phone, String code) {
        this.phone = phone;
        this.code = code;
    }

    @Override
    public Object getPrincipal() {
        return phone;
    }

    @Override
    public Object getCredentials() {
        return code;
    }
}

同时需要实现SmsRealm,在认证方法中进行手机号和验证码的比对。

public class SmsRealm extends AuthenticatingRealm {
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        SmsToken token = (SmsToken) authenticationToken;
        String phone = token.getPrincipal().toString();
        String code = token.getCredentials().toString();

        //查询手机号和验证码是否匹配
        if (!"123456".equals(code)) {
            throw new AuthenticationException("验证码错误");
        }

        return new SimpleAuthenticationInfo(phone, code, getName());
    }
}

完整代码可以参考以下示例:

@Configuration
public class ShiroConfiguration {
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");

        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/doLogin", "anon");
        filterChainDefinitionMap.put("/login/sms", "anon");
        filterChainDefinitionMap.put("/doSmsLogin", "anon");
        filterChainDefinitionMap.put("/logout", "logout");
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return shiroFilterFactoryBean;
    }

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

    @Bean
    public MyRealm myRealm() {
        return new MyRealm();
    }

    @Bean
    public SmsRealm smsRealm() {
        return new SmsRealm();
    }
}

public class MyRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //授权方法
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username = token.getUsername();
        String password = new String(token.getPassword());

        //根据用户名和密码查询用户信息,可以通过MyBatis进行数据库操作
        User user = userService.findByUsernameAndPassword(username, password);
        if (user == null) {
            throw new UnknownAccountException("用户名或密码错误");
        }

        return new SimpleAuthenticationInfo(username, password, getName());
    }
}

public class SmsRealm extends AuthenticatingRealm {
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        SmsToken token = (SmsToken) authenticationToken;
        String phone = token.getPrincipal().toString();
        String code = token.getCredentials().toString();

        //查询手机号和验证码是否匹配
        if (!"123456".equals(code)) {
            throw new AuthenticationException("验证码错误");
        }

        return new SimpleAuthenticationInfo(phone, code, getName());
    }
}

@Controller
public class LoginController {
    @GetMapping("/login")
    public String login() {
        return "login";
    }

    @GetMapping("/logout")
    public String logout() {
        return "logout";
    }

    @PostMapping("/doLogin")
    public String doLogin(String username, String password) {
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(token);
            return "redirect:/index";
        } catch (AuthenticationException e) {
            return "error";
        }
    }

    @GetMapping("/login/sms")
    public String smsLogin() {
        return "login_sms";
    }

    @PostMapping("/doSmsLogin")
    public String doSmsLogin(String phone, String code) {
        SmsToken token = new SmsToken(phone, code);
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(token);
            return "redirect:/index";
        } catch (AuthenticationException e) {
            return "error";
        }
    }
}

其中包括了一个基本的登录页面、验证码登录页面,以及对应的Controller。在前端页面的form中添加对应的input即可实现不同方式的登录。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:springboot整合shiro多验证登录功能的实现(账号密码登录和使用手机验证码登录) - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • 五分钟解锁springboot admin监控新技巧

    五分钟解锁 Spring Boot Admin 监控新技巧 Spring Boot Admin 是一个用于监控和管理 Spring Boot 应用程序的开源项目。本文将介绍如何在 5 分钟内轻松启用和配置 Spring Boot Admin 监控。 步骤一:添加 Spring Boot Admin 依赖项 首先,需要添加以下 Spring Boot Admi…

    Java 2023年5月20日
    00
  • Java中ArrayList的使用详细介绍

    可以的,下面是关于Java中ArrayList使用详细介绍的完整攻略。 什么是ArrayList? ArrayList是Java中的一个动态数组,具有自动扩容功能。与Java中的数组相比,ArrayList能够更加灵活地操作元素,而且能够自动处理数组的长度。 如何使用ArrayList? 要使用ArrayList,你需要遵循以下步骤: 1. 导入java.u…

    Java 2023年5月26日
    00
  • 什么是垃圾回收器?

    以下是关于垃圾回收器的完整使用攻略: 什么是垃圾回收器? 垃圾回收器是一种自动内存管理机制,用于在程序运行时自动回收不再使用的内存空间。垃圾回收器可以检测和回收不再使用的内存空间,以便其他程序或操作系统可以使用该内存空间。垃圾回收器通常用于高级编程语言中,如Java、Python等。 垃圾回收器的示例1:Java中的垃圾回收器 Java中的垃圾回收器是一种自…

    Java 2023年5月12日
    00
  • 微信小程序实现手写签名(签字版)

    实现手写签名的微信小程序,其主要思路就是利用画布(canvas)实现用户在手机上进行手写签名的功能。下面是具体的实现攻略: 步骤一:创建画布(canvas) 首先,在小程序页面的wxml文件中创建一个canvas,如下所示: <canvas canvas-id="myCanvas" style="width: 100%; …

    Java 2023年5月23日
    00
  • 使用Spring处理x-www-form-urlencoded方式

    要使用Spring处理x-www-form-urlencoded方式,需要进行以下步骤: 配置Spring MVC 在web.xml中配置DispatcherServlet。在DispatcherServlet的xml配置文件中,添加,启用Spring MVC注解驱动。这样Spring MVC就可以自动处理表单提交请求。 编写Controller Sprin…

    Java 2023年5月20日
    00
  • 使用Maven Helper解决Maven插件冲突的方法

    使用Maven进行项目构建时,不可避免地会涉及到多个依赖库之间的版本冲突问题,特别是在使用多个Maven插件时更容易发生冲突。而Maven Helper是一款方便的插件,能够帮助我们解决这些冲突。下面是使用Maven Helper解决Maven插件冲突的方法: 1. 安装Maven Helper插件 首先需要在Maven项目中安装Maven Helper插件…

    Java 2023年5月20日
    00
  • JAVA中的for循环几种使用方法讲解

    JAVA中的for循环几种使用方法讲解 在Java中,for循环是最常用的循环结构之一。它可以重复执行代码块,根据不同的循环条件可以有多种使用方式。 基本的for循环 最基本的for循环有三个部分,分别是循环变量初始化、循环条件和循环变量的更新。语法如下: for (循环变量初始化; 循环条件; 循环变量的更新) { // 循环体代码块 } 其中,循环变量初…

    Java 2023年5月26日
    00
  • Java操作Mysql的方法

    关于Java操作MySQL的方法,需要掌握以下几点: 导入数据库驱动程序 建立数据库连接 创建statement对象,执行SQL语句 处理查询结果集 关闭各种连接 下面将详细介绍这些步骤以及如何实现它们。 导入数据库驱动程序 在Java中操作MySQL,需要先导入MySQL的JDBC驱动程序。如果你使用的是Maven等依赖管理工具,可以直接在pom.xml中…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部