当前位置: 首页 > article >正文

Spring Boot集成Shiro认证

在现代Web开发中,安全性是至关重要的。Shiro是一个强大的Java安全框架,提供了认证、授权、加密和会话管理等功能。本文将详细介绍如何在Spring Boot项目中集成Shiro进行用户认证。

一、项目准备

首先,我们需要创建一个Spring Boot项目,并添加必要的依赖。在pom.xml文件中添加Shiro、MyBatis、数据库驱动和Thymeleaf等依赖:

<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis Starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<!-- Thymeleaf Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- Shiro Spring Integration -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.8.0</version>
</dependency>
<!-- Database Driver (e.g., MySQL) -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
二、数据库和实体类

创建一个数据库和用户表,用于存储用户信息。例如,一个简单的用户表结构如下:

CREATE TABLE user (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(100) NOT NULL,
salt VARCHAR(50),
realname VARCHAR(100)
);

然后,在Spring Boot项目中创建一个对应的实体类User,并使用JPA注解进行映射:

import javax.persistence.*;
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "username")
private String username;
@Column(name = "password")
private String password;
@Column(name = "salt")
private String salt;
@Column(name = "realname")
private String realname;
// Getters and Setters
}
三、配置Shiro

创建一个Shiro配置类ShiroConfig,配置Shiro的安全管理器、Realm和过滤器链:

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm());
return securityManager;
}
@Bean
public MyRealm myRealm() {
MyRealm realm = new MyRealm();
realm.setCredentialsMatcher(credentialsMatcher());
return realm;
}
@Bean
public HashedCredentialsMatcher credentialsMatcher() {
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("SHA-256");
matcher.setHashIterations(1024);
return matcher;
}
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSuccessUrl("/");
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/css/**", "anon");
filterChainDefinitionMap.put("/js/**", "anon");
filterChainDefinitionMap.put("/fonts/**", "anon");
filterChainDefinitionMap.put("/img/**", "anon");
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/logout", "logout");
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
}
四、自定义Realm

创建一个自定义的Realm类MyRealm,用于处理用户的认证和授权逻辑:

import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = (String) principals.getPrimaryPrincipal();
User user = userService.findByUsername(username);
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.addRoles(user.getRoles());
authorizationInfo.addStringPermissions(user.getPermissions());
return authorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String username = upToken.getUsername();
User user = userService.findByUsername(username);
if (user == null) {
throw new UnknownAccountException("用户不存在");
}
ByteSource salt = ByteSource.Util.bytes(user.getSalt());
return new SimpleAuthenticationInfo(username, user.getPassword(), salt, getName());
}
}
五、业务层和服务层

创建一个UserService接口和实现类,用于访问数据库中的用户信息:

import org.springframework.stereotype.Service;
import java.util.List;
public interface UserService {
User findByUsername(String username);
// 其他方法...
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User findByUsername(String username) {
List<User> users = userMapper.findAll();
for (User user : users) {
if (user.getUsername().equals(username)) {
return user;
}
}
return null;
}
// 其他实现...
}

创建一个UserMapper接口和对应的XML映射文件,用于MyBatis操作数据库:

import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface UserMapper {
List<User> findAll();
}

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
<select id="findAll" resultType="com.example.demo.beans.User">
SELECT * FROM user
</select>
</mapper>
六、控制器和视图

创建一个控制器类,用于处理登录请求和受保护的资源请求:

package com.bdqn.controller;

import com.bdqn.pojo.Right;
import com.bdqn.pojo.Role;
import com.bdqn.pojo.User;
import com.bdqn.service.RoleService;
import com.bdqn.service.UserService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpSession;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import java.util.List;

/**
 * 登录注销相关控制器
 *
 * @author LILIBO
 * @since 2024/9/21
 */
@Controller
public class IndexController {

    @Resource
    private UserService userService;

    @Resource
    private RoleService roleService;

    /**
     * 去登录页
     */
    @GetMapping("/login")
    public String toLogin() {
        return "login";
    }

    /**
     * 执行登录操作
     */
    @PostMapping("/login")
    public String doLogin(HttpSession session, String usrName, String usrPassword, Model model) {
//        User loginUser = userService.login(usrName, usrPassword);
//        session.setAttribute("loginUser", loginUser);
//        return "redirect:/main";
        try {
            UsernamePasswordToken token=new UsernamePasswordToken(usrName,usrPassword);
            Subject subject= SecurityUtils.getSubject();
            subject.login(token);
            // 认证(登录)成功

            User user=(User) subject.getPrincipal();
            Role role  = user.getRole();
            List<Right> rights = roleService.getRigthsByRoleId(role);
            role.getRights().addAll(rights);
            session.setAttribute("loginUser",user);
            return "redirect:/main";
        }catch (UnknownAccountException | IncorrectCredentialsException e){
            model.addAttribute("message","用户名或密码失败,登录失败!");
            return "login";
        }catch (LockedAccountException e){
            model.addAttribute("message","用户被禁用,登录失败!");
            return "login";
        }catch (AuthenticationException e){
            model.addAttribute("message","认证异常,登录失败!");
            return "login";
        }
    }

    /**
     * 跳转到主页
     */
    @GetMapping("/main")
    public String toMain() {
        return "main";
    }

    /**
     * 退出登录
     */
    @GetMapping("/logout")
    public String logout(HttpSession session) {
        session.removeAttribute("loginUser");
        SecurityUtils.getSubject().logout();
        return "redirect:/login";
    }
    @GetMapping("/403")
    public String to403(){
        return "403";
    }


}


http://www.kler.cn/news/363547.html

相关文章:

  • 保姆级教程来喽!从下载开始的Luatools~小白必看!
  • ONLYOFFICE 文档8.2版本已发布:PDF 协作编辑、改进界面、性能优化等更新
  • 一招教你解决Facebook广告账号问题
  • 【NOIP普及组】 装箱问题
  • shell脚本-函数
  • 数据库中DDL、DML、DCL的区别是什么
  • Android 两种方式实现类似水波扩散效果
  • 手机pdf阅读器,用手机也能够阅读、编辑pdf文件
  • 右键以vscode打开目录的时候出现找不到应用程序
  • 亿佰特CAN转422、232、485模块解决高于115200波特率时设备失联问题
  • 一文掌握 jetbrains IDE 新 UI,还不会新 UI 的同学快看过来
  • OpenMediaVault安装插件以及重置web控制台密码
  • 软考攻略/超详细/系统集成项目管理工程师/基础知识分享18
  • Uefi Application小游戏开发之推箱子
  • idea启动报错:com.intellij.diagnostic.PluginException
  • 【数据结构】专栏开篇 | 1024程序员节
  • 信息库:Air780E量产binpkg文件的获取途径探究!
  • EureKa是什么?
  • 内存溢出与内存泄漏详解!
  • goframe开发一个企业网站 权限设计1
  • 初始JavaEE篇——多线程(3):可重入锁、死锁、内存可见性、volatile关键字
  • 网络应用层
  • 深入浅出理解BLE AUDIO CSIS
  • 深入探究安卓 Binder 机制及其应用
  • 学习虚幻C++开发日志——TSet
  • Oracle 更换监听端口