springboot集成shiro和前后端分离配置

server/2024/11/27 1:11:39/

一,springboot集成shiro

1,导入依赖

        <dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring-boot-starter</artifactId><version>1.4.0</version></dependency>

2,Realm

shiro以来这个来进行认证和授权

java">package com.chen.admin.Realm;import com.alibaba.fastjson.JSON;
import com.chen.admin.dto.UserDto;
import com.chen.admin.entity.Role;
import com.chen.admin.entity.User;
import com.chen.admin.service.RoleService;
import com.chen.admin.service.UserService;
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.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;import java.util.*;/*** @Author @Chenxc* @Date 24-7-2 10:13*/
@Component
public class UserPasswordRealm extends AuthorizingRealm {@Autowiredprivate RoleService roleService;@Autowiredprivate UserService userService;@Autowiredprivate PasswordEncoder encoder;// @Autowired//private StringRedisTemplate stringRedisTemplate;//授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {UserDto user = (UserDto) principalCollection.getPrimaryPrincipal();//使用redis存放用户角色和权限
//        Object o = stringRedisTemplate.opsForValue().get("user:" + user.getId());
//        if(null == o){
//            List<Role> roleList = roleService.getRoleByUserId(user.getId());
//            if(null != roleList){
//                Set<String> roles = new HashSet<>();
//                Set<String> permissions = new HashSet<>();
//                for (Role role : roleList) {
//                    roles.add(role.getName());
//                    List<String> permission = roleService.getPermissionByRoleId(role.getId());
//                    if(null != permission){
//                        permissions.addAll(permission);
//                    }
//                }
//                user.setRoleList(roles);
//                user.setPermissions(permissions);
//            }
//            stringRedisTemplate.opsForValue().set("user:"+user.getId(), JSON.toJSONString(user));
//        }else{
//            String json = (String)o;
//            user = JSON.parseObject(json,UserDto.class);
//        }
//        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
//        simpleAuthorizationInfo.addRoles(user.getRoleList());
//        simpleAuthorizationInfo.addStringPermissions(user.getPermissions());//本地存放用户角色和权限List<Role> roleList = roleService.getRoleByUserId(user.getId());if(null != roleList){Set<String> roles = new HashSet<>();Set<String> permissions = new HashSet<>();for (Role role : roleList) {roles.add(role.getName());List<String> permission = roleService.getPermissionByRoleId(role.getId());if (null != permission) {permissions.addAll(permission);}}user.setRoleList(roles);user.setPermissions(permissions);}SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();simpleAuthorizationInfo.addRoles(user.getRoleList());simpleAuthorizationInfo.addStringPermissions(user.getPermissions());return simpleAuthorizationInfo;}//认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;String username = token.getUsername();char[] password1 = token.getPassword();if(null == username || null  == password1){throw new AuthenticationException("用户名或密码错误");}String password = new String(password1);User user = userService.getUserByUsername(username);if(null == user){throw new AuthenticationException("用户名或密码错误");}boolean matches = encoder.matches(password, user.getPassword());if (!matches) {throw new AuthenticationException("用户名或密码错误");}if(user.getEnable().equals("0")){throw new DisabledAccountException("用户已禁用");}UserDto dto = new UserDto();BeanUtils.copyProperties(user,dto);SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(dto, password, getName());return authenticationInfo;}
}

3,shiro配置

java">package com.chen.admin.config;import com.chen.admin.dao.RedisSessionDao;
import com.chen.admin.filter.ShiroFormAuthenticationFilter;
import com.chen.admin.system.Constant;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;/*** @Author @Chenxc* @Date 24-7-2 10:10*/
@Configuration
public class ShiroConfig {@Beanpublic DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();// 设置为true则会在代理对象的方法执行过程中进行权限校验defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);return defaultAdvisorAutoProxyCreator;}@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();advisor.setSecurityManager(securityManager);return advisor;}//上面的两个开启注解的支持,如果没有这两个方法,doGetAuthorizationInfo不会执行,加了@RequiresPermissions注解后会包找不到url//session保存在内存@Beanpublic DefaultWebSessionManager defaultWebSessionManager(){DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();sessionManager.setGlobalSessionTimeout(Constant.expireTime * 1000);sessionManager.setDeleteInvalidSessions(true);sessionManager.setSessionValidationSchedulerEnabled(true);//修改Cookie中的SessionId的key,默认为JSESSIONID,自定义名称sessionManager.setSessionIdCookie(new SimpleCookie(Constant.SHIRO_COOKIE_ID));return sessionManager;}//session保存在redis@Beanpublic DefaultWebSessionManager defaultWebSessionManager(RedisSessionDao redisSessionDao){DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();sessionManager.setGlobalSessionTimeout(Constant.expireTime * 1000);sessionManager.setDeleteInvalidSessions(true);sessionManager.setSessionDAO(redisSessionDao);sessionManager.setSessionValidationSchedulerEnabled(true);//修改Cookie中的SessionId的key,默认为JSESSIONID,自定义名称sessionManager.setSessionIdCookie(new SimpleCookie(Constant.SHIRO_COOKIE_ID));return sessionManager;}//上面的session存放选一个即可@Beanpublic DefaultWebSecurityManager defaultWebSecurityManager(DefaultWebSessionManager defaultWebSessionManager,Realm realm){DefaultWebSecurityManager manager = new DefaultWebSecurityManager();// 取消Cookie中的RememberMe参数manager.setRememberMeManager(null);manager.setRealm(realm);manager.setSessionManager(defaultWebSessionManager);return manager;}@Beanpublic ShiroFilterFactoryBean shiroFilterChainDefinition(DefaultWebSecurityManager defaultWebSecurityManager) {ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();factoryBean.setSecurityManager(defaultWebSecurityManager);factoryBean.setLoginUrl("/login");//factoryBean.setSuccessUrl("/loginSuccess");Map<String, String> map = new LinkedHashMap<>();//map.put("/login","anon");map.put("/static/**","anon");map.put("/ws/**","authc");map.put("/**", "authc");// 配置shiro默认登录界面地址,前后端分离中登录界面跳转应由前端路由控制,后台仅返回json数据
//        shiroFilterFactoryBean.setLoginUrl("/login/unauth");LinkedHashMap<String, Filter> filtsMap = new LinkedHashMap<>();// 这里使用自定义的filterfiltsMap.put("authc", new ShiroFormAuthenticationFilter());factoryBean.setFilters(filtsMap);factoryBean.setFilterChainDefinitionMap(map);return factoryBean;}}

如果上面使用redis还需要集成 AbstractSessionDAO 来读取redis中的数据来认证和授权

RedisSessionDao:

java">package com.chen.admin.dao;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.chen.admin.system.Constant;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.util.JSONPObject;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SimpleSession;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Collection;
import java.util.concurrent.TimeUnit;/**shiro集成redis* @author @Chenxc* @date 2024/7/3 0:46**/@Component
public class RedisSessionDao extends AbstractSessionDAO {@Autowiredprivate RedisTemplate redisTemplate;@Overrideprotected Serializable doCreate(Session session) {Serializable serializable = this.generateSessionId(session);this.assignSessionId(session,serializable);redisTemplate.opsForValue().set(session.getId(),session, Constant.expireTime, TimeUnit.SECONDS);return serializable;}@Overrideprotected Session doReadSession(Serializable serializable) {if(serializable == null){return null;}SimpleSession o = (SimpleSession)redisTemplate.opsForValue().get(serializable);if(o == null){return null;}return o;}@Overridepublic void update(Session session) throws UnknownSessionException {if(session != null && session.getId() != null){session.setTimeout( Constant.expireTime * 1000);redisTemplate.opsForValue().set(session.getId(),session, Constant.expireTime,TimeUnit.SECONDS);}}@Overridepublic void delete(Session session) {if (session != null && session.getId() != null) {redisTemplate.opsForValue().getOperations().delete(session.getId());}}@Overridepublic Collection<Session> getActiveSessions() {return redisTemplate.keys("*");}
}

二,前后端分离配置

如果是前后端分离中登录界面跳转应由前端路由控制,后台仅返回json数据,可以继承FormAuthenticationFilter重写里面的两个方法即可:

java">org.apache.shiro.web.filter.authc.FormAuthenticationFilter#onAccessDenied
org.apache.shiro.web.filter.authc.FormAuthenticationFilter#onLoginSuccess
java">package com.chen.admin.filter;import com.alibaba.fastjson.JSON;
import com.chen.admin.system.Result;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;/*** @author @Chenxc* @date 2024/7/8 1:29**/
public class ShiroFormAuthenticationFilter extends FormAuthenticationFilter {private static final Logger log = LoggerFactory.getLogger(ShiroFormAuthenticationFilter.class);/** 未登录时返回json* @auther: @Chenxc		//作者* @Description //TODO 	//描述* @param: 	//参数* @return: 	//返回值* @date:  	//创建日期*/@Overrideprotected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {if (this.isLoginRequest(request, response)) {if (this.isLoginSubmission(request, response)) {if (log.isTraceEnabled()) {log.trace("Login submission detected.  Attempting to execute login.");}return this.executeLogin(request, response);} else {if (log.isTraceEnabled()) {log.trace("Login page view.");}return true;}} else {if (log.isTraceEnabled()) {log.trace("Attempting to access a path which requires authentication.  Forwarding to the Authentication url [" + this.getLoginUrl() + "]");}//this.saveRequestAndRedirectToLogin(request, response);response.setContentType("application/json; charset=utf-8");response.setCharacterEncoding("UTF-8");PrintWriter out = response.getWriter();out.println(JSON.toJSONString(Result.unauthenticated()));out.flush();out.close();return false;}}/** 登录成功后返回json* @auther: @Chenxc		//作者* @Description //TODO 	//描述* @param: 	//参数* @return: 	//返回值* @date:  	//创建日期*/@Overrideprotected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {if (log.isTraceEnabled()) {log.trace("Attempting to access a path which requires authentication.  Forwarding to the Authentication url [" + this.getLoginUrl() + "]");}//this.saveRequestAndRedirectToLogin(request, response);response.setContentType("application/json; charset=utf-8");response.setCharacterEncoding("UTF-8");PrintWriter out = response.getWriter();Result result = Result.success("登录成功");HttpServletResponse httpServletResponse = (HttpServletResponse) response;String header = httpServletResponse.getHeader("Set-Cookie");if(null != header){String[] split = header.split(";");if(null != split && split.length != 0){String tokenStr = split[0].split("=")[1];result.setData(tokenStr);}}out.println(JSON.toJSONString(result));out.flush();out.close();return false;}
}

最后controller

java">package com.chen.admin.controller;import com.chen.admin.entity.Menu;
import com.chen.admin.service.MenuService;
import com.chen.admin.system.Result;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @author @Chenxc* @date 2024/7/15 23:46**/
@RestController
@RequestMapping("/menu")
@RequiresPermissions({"MENU"})//访问该controller需要的权限
public class MenuController {@Autowiredprivate MenuService menuService;@RequestMapping("/list")public Result<Menu> list(){return menuService.menuList();}@RequestMapping("/save")public Result<Menu> save(Menu menu){return menuService.saveMenu(menu);}@RequestMapping("/delete")public Result delete(Long id){return menuService.delete(id);}@RequestMapping("/update")public Result update(Menu menu){return menuService.updateMenu(menu);}}

http://www.ppmy.cn/server/145199.html

相关文章

react项目初始化配置步骤

1.npx create-react-app 项目名称 vue项目同理 2.去编辑器市场安装所需插件&#xff0c;例如ESlint以及Prettier-Code formatter formatiing-toggle 3.在项目中安装 ESLint 和 Prettier 及相关插件&#xff1a; 3.1&#xff1a; npm install --save-dev eslint prettier 3.2…

wp the_posts_pagination 与分类页面搭配使用

<ul> <?php while( have_posts() ) : the_post(); <li > <a href"<?php the_permalink(); ?>"> <?php xizhitbu_get_thumbnail(thumb-pro); ?> </a> <p > <a href&q…

Redis Key 命名规范文档

开发过程中为确保 Redis 键名的一致性、可读性和易维护性&#xff0c;本规范旨在指导开发团队在使用 Redis 时设计合理的键名格式。 1. 命名格式 采用 模块:子模块:业务描述:标识 的分层格式&#xff0c;明确数据来源和用途。 层次清晰&#xff1a;从全局到具体逐步细化。唯一…

构建 Java Web 应用程序:从 Servlet 到数据库交互(Eclipse使用JDBC连接Mysql数据库)

第 1 部分&#xff1a;环境设置 安装 Java Development Kit (JDK)&#xff1a;下载并安装 JDK。设置 IDE&#xff1a;安装并配置 IDE&#xff08;如 IntelliJ IDEA 或 Eclipse&#xff09;。安装数据库&#xff1a;下载并安装 MySQL 数据库。配置数据库&#xff1a;创建数据库…

基于matlab的电力系统潮流计算

1、内容简介 略 94-可以交流、咨询、答疑 2、内容说明 电力系统潮流计算是最基本、最常用的计算。根据系统给定的运行条件、网络及元件参数&#xff0c;通过电力系统潮流计算可以确定各母线上的电压&#xff08;幅值及相角&#xff09;、网络中的功率发布以及功率损耗等。电力…

Spring Boot 应用开发:构建高效、可扩展的 Java 微服务

以下是一个简单的 Spring Boot 小项目示例&#xff0c;该项目是一个基于 Spring Boot 的博客系统后端部分。这个项目将展示如何使用 Spring Boot 框架来创建一个基本的 RESTful API 服务&#xff0c;以管理博客文章。 项目结构 spring-boot-blog ├── src │ ├── main…

Claude Opus MetaPrompt 系统详解

Claude Opus MetaPrompt 系统详解 简介 MetaPrompt系统是由Anthropic提出的&#xff0c;旨在帮助用户为AI助手Claude生成高质量的提示。它指导用户定义任务和变量、结构化指令和细化输出。 具体内容 特点 主要针对Claude 3 Opus版本&#xff0c;并且适用于单轮对话。 核心…

基于开源 AI 智能名片 2+1 链动模式 S2B2C 商城小程序源码的社交新零售利益共同体构建与发展研究

摘要&#xff1a;本论文聚焦于社交新零售这一新兴商业模式&#xff0c;深入探讨其在开源 AI 智能名片 21 链动模式 S2B2C 商城小程序源码支撑下&#xff0c;如何构建并发展人与人之间的利益共同体。通过对相关概念的剖析、模式的解析以及案例的研究&#xff0c;揭示了这种创新模…