Shiro安全认证技术实践

为Java后端项目添加Shiro进行身份验证,授权操作:

步骤1.引入相关依赖:

html 复制代码
<dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-spring-boot-starter</artifactId>
  <version>1.9.1</version> <!-- 确保使用最新版本 -->
</dependency>

步骤2.配置shiro.ini

在resources目录下进行添加shiro.ini文件

html 复制代码
[main]
# Realm配置
myRealm = org.apache.shiro.realm.jdbc.JdbcRealm
myRealm.dataSource = myDataSource

# 使用自定义Realm
securityManager.realms = $myRealm

[users]
# 用户名 = 密码, 角色
admin = secret, admin
guest = guest, guest

[roles]
# 角色 = 权限
admin = *
guest = read
user = read

步骤3.配置ShiroConfig

在config目录下创建ShiroConfig.java文件

java 复制代码
package com.cetide.oj.config;

import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.authz.ModularRealmAuthorizer;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.session.mgt.DefaultSessionManager;
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 javax.sql.DataSource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

    @Bean
    public Realm myRealm() {
        // 返回你自己的 Realm 实现
        return new MyRealm();
    }

    @Bean
    public ModularRealmAuthenticator authenticator() {
        ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();
        authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
        authenticator.setRealms(Arrays.asList(myRealm()));
        return authenticator;
    }

    @Bean
    public ModularRealmAuthorizer authorizer() {
        ModularRealmAuthorizer authorizer = new ModularRealmAuthorizer();
        authorizer.setRealms(Arrays.asList(myRealm()));
        return authorizer;
    }
    @Bean
    public SecurityManager securityManager(DataSource dataSource) {
        JdbcRealm realm = new JdbcRealm();
        realm.setDataSource(dataSource);

        // 配置Realm的用户查询和角色查询
        realm.setPermissionsLookupEnabled(true); // 启用权限查找
        // 你可以在这里设置自定义的SQL查询以获取用户和角色信息

        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(realm);
        return securityManager;
    }

    @Bean
    public DefaultSessionManager sessionManager() {
        DefaultSessionManager sessionManager = new DefaultSessionManager();
        return sessionManager;
    }
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
        filterFactoryBean.setSecurityManager(securityManager);

        // 配置访问路径
        Map<String, String> filterChainDefinitionMap = new HashMap<>();
        filterChainDefinitionMap.put("/admin/**", "roles[admin]");
        filterChainDefinitionMap.put("/guest/**", "roles[guest]");
        filterChainDefinitionMap.put("/**", "anon"); // 允许匿名访问
        filterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return filterFactoryBean;
    }
}

步骤4.配置自定义MyRealm

java 复制代码
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;

public class MyRealm extends AuthorizingRealm {

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = (String) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        if ("admin".equals(username)) {
            info.addRole("admin");
            info.addStringPermission("*"); // admin有所有权限
        } else if ("guest".equals(username)) {
            info.addRole("guest");
            info.addStringPermission("read"); // guest仅有读取权限
        }
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username = (String) token.getPrincipal();
        String password = new String((char[]) token.getCredentials());

        // 模拟数据库查询
        if ("admin".equals(username) && "123456".equals(password)) {
            return new SimpleAuthenticationInfo(username, password, getName());
        } else {
            throw new UnknownAccountException("用户名或密码错误");
        }
    }
}

步骤5.引入到Controller中

java 复制代码
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class HomeController {
    @PostMapping("/login")
    public String login(String username, String password) {
        Subject currentUser = SecurityUtils.getSubject();

        if (!currentUser.isAuthenticated()) {
            // 创建一个用户认证的token
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            try {
                // 执行登录操作
                currentUser.login(token);
                if (currentUser.hasRole("admin")) {
                    return "admin"; // 返回管理员视图
                }
                return "403"; // 无权限视图
            } catch (Exception e) {
                e.printStackTrace();
                return "loginError"; // 登录失败,返回错误视图
            }
        }

        return "redirect:/"; // 已经登录,重定向到主页
    }

    @RequestMapping("/logout")
    public String logout() {
        Subject currentUser = SecurityUtils.getSubject();
        if (currentUser.isAuthenticated()) {
            currentUser.logout(); // 执行注销
        }
        return "redirect:/"; // 注销后重定向到主页
    }
    @GetMapping("/")
    public String home() {
        return "index"; // 返回主页视图
    }

    @GetMapping("/admin")
    public String admin() {
        Subject currentUser = SecurityUtils.getSubject();
        if (currentUser.hasRole("admin")) {
            return "admin"; // 返回管理员视图
        }
        return "403"; // 无权限视图
    }

    @GetMapping("/guest")
    public String guest() {
        return "guest"; // 返回访客视图
    }
}
相关推荐
用户962377954482 天前
DVWA 靶场实验报告 (High Level)
安全
数据智能老司机2 天前
用于进攻性网络安全的智能体 AI——在 n8n 中构建你的第一个 AI 工作流
人工智能·安全·agent
数据智能老司机2 天前
用于进攻性网络安全的智能体 AI——智能体 AI 入门
人工智能·安全·agent
用户962377954482 天前
DVWA 靶场实验报告 (Medium Level)
安全
red1giant_star2 天前
S2-067 漏洞复现:Struts2 S2-067 文件上传路径穿越漏洞
安全
用户962377954482 天前
DVWA Weak Session IDs High 的 Cookie dvwaSession 为什么刷新不出来?
安全
cipher4 天前
ERC-4626 通胀攻击:DeFi 金库的"捐款陷阱"
前端·后端·安全
一次旅行7 天前
网络安全总结
安全·web安全
red1giant_star7 天前
手把手教你用Vulhub复现ecshop collection_list-sqli漏洞(附完整POC)
安全
ZeroNews内网穿透7 天前
谷歌封杀OpenClaw背后:本地部署或是出路
运维·服务器·数据库·安全