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"; // 返回访客视图
    }
}
相关推荐
tq023 小时前
Cookie和Seeion在客户端和服务端的角色作用
运维·服务器·安全
青衫客364 小时前
浅谈 Protobuf——高效、安全的跨语言通信基石
服务器·安全·远程调用·protobuf
Digitally4 小时前
如何安全轻松地出售损坏的 iPhone(最新指南)
安全·ios·iphone
乐迪信息7 小时前
乐迪信息:智慧煤矿输送带安全如何保障?AI摄像机全天候识别
大数据·运维·人工智能·安全·自动化·视觉检测
知孤云出岫7 小时前
为 AI / LLM / Agent 构建安全基础
人工智能·安全
00后程序员张7 小时前
Windows 安全分割利器:strtok_s () 详解
windows·单片机·安全
牛奶咖啡138 小时前
解决MySQL8.0及其更高版本的两个安全问题——及其配置MySQL实现SSL/TLS加密通信、caching_sha2_password通信
安全·mysql8.0·明文密码登录mysql不安全·忘记mysql用户密码解决方法·mysql主从复制请求安全连接·从库获取主库公钥实现加密通信·mysql配置ssl实现加密
yuezhilangniao9 小时前
Wazuh vs. 安全洋葱:开源SOC核心平台用哪个呢?
安全
国科安芯9 小时前
核辐射检测仪中的抗辐照MCU芯片应用探索与挑战应对
网络·人工智能·单片机·嵌入式硬件·安全·fpga开发
DeafReady10 小时前
SRC漏洞挖以及掘提交平台
网络·安全