登陆后@PreAuthorize校验

news/2024/9/23 16:14:54/

用户登录:断点看流程认证

之前我们知道

java">生成令牌之后,我们就调用全局保存令牌
SecurityContextHolder.getContext().setAuthentication(authentication);

SecurityContextHolder.getContext()获取的是SecurityContext就是设置令牌和保存令牌

java">/** Copyright 2004, 2005, 2006 Acegi Technology Pty Limited** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      https://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package org.springframework.security.core.context;import java.io.Serializable;import org.springframework.security.core.Authentication;/*** Interface defining the minimum security information associated with the current thread* of execution.** <p>* The security context is stored in a {@link SecurityContextHolder}.* </p>** @author Ben Alex*/
public interface SecurityContext extends Serializable {/*** Obtains the currently authenticated principal, or an authentication request token.* @return the <code>Authentication</code> or <code>null</code> if no authentication* information is available*/Authentication getAuthentication();/*** Changes the currently authenticated principal, or removes the authentication* information.* @param authentication the new <code>Authentication</code> token, or* <code>null</code> if no further authentication information should be stored*/void setAuthentication(Authentication authentication);}

之前的令牌我们存的是
public class JwtUserDto implements UserDetails
里面又三个属性

 private final User user;private final List<Long> dataScopes;private final List<AuthorityDto> authorities;

但是UserDetails接口并没有这三个属性的获取方法而存入令牌的就是UserDetails类

看一下UserDetails接口(里面没有我们三个属性的方法)

java">/** Copyright 2004, 2005, 2006 Acegi Technology Pty Limited** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      https://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package org.springframework.security.core.userdetails;import java.io.Serializable;
import java.util.Collection;import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;/*** Provides core user information.** <p>* Implementations are not used directly by Spring Security for security purposes. They* simply store user information which is later encapsulated into {@link Authentication}* objects. This allows non-security related user information (such as email addresses,* telephone numbers etc) to be stored in a convenient location.* <p>* Concrete implementations must take particular care to ensure the non-null contract* detailed for each method is enforced. See* {@link org.springframework.security.core.userdetails.User} for a reference* implementation (which you might like to extend or use in your code).** @author Ben Alex* @see UserDetailsService* @see UserCache*/
public interface UserDetails extends Serializable {/*** Returns the authorities granted to the user. Cannot return <code>null</code>.* @return the authorities, sorted by natural key (never <code>null</code>)*/Collection<? extends GrantedAuthority> getAuthorities();/*** Returns the password used to authenticate the user.* @return the password*/String getPassword();/*** Returns the username used to authenticate the user. Cannot return* <code>null</code>.* @return the username (never <code>null</code>)*/String getUsername();/*** Indicates whether the user's account has expired. An expired account cannot be* authenticated.* @return <code>true</code> if the user's account is valid (ie non-expired),* <code>false</code> if no longer valid (ie expired)*/boolean isAccountNonExpired();/*** Indicates whether the user is locked or unlocked. A locked user cannot be* authenticated.* @return <code>true</code> if the user is not locked, <code>false</code> otherwise*/boolean isAccountNonLocked();/*** Indicates whether the user's credentials (password) has expired. Expired* credentials prevent authentication.* @return <code>true</code> if the user's credentials are valid (ie non-expired),* <code>false</code> if no longer valid (ie expired)*/boolean isCredentialsNonExpired();/*** Indicates whether the user is enabled or disabled. A disabled user cannot be* authenticated.* @return <code>true</code> if the user is enabled, <code>false</code> otherwise*/boolean isEnabled();}

要定义一个工具类SecurityUtils获取令牌里的值
问题:获取用户属性里面数据怎么获取?

看类SecurityUtils
getCurrentUser方法(所以贴了SpringContextHolder类):
在获取登录用户用到类SpringContextHolder去找UserDetailsService

主要看getCurrentUsername这个方法里调用
SecurityContextHolder.getContext().getAuthentication()获取令牌后获取usernanme(这就是为啥一开始SecurityContextHolder.getContext().setAuthentication(authentication);这代码的用处)

答案就是用json(工具类下这几个方法)
getCurrentUserRole
getCurrentUserId
getCurrentUserDataScope

java">package com.njry.utils;import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.njry.exception.BadRequestException;
import com.njry.utils.enums.DataScopeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;/*** 获取当前登录的用户* @author * @date 2024-05-11*/
@Slf4j
public class SecurityUtils {/*** 获取当前登录的用户* @return UserDetails*/public static UserDetails getCurrentUser() {UserDetailsService userDetailsService = SpringContextHolder.getBean(UserDetailsService.class);return userDetailsService.loadUserByUsername(getCurrentUsername());}/*** 获取系统用户名称** @return 系统用户名称*/public static String getCurrentUsername() {final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();if (authentication == null) {throw new BadRequestException(HttpStatus.UNAUTHORIZED, "当前登录状态过期");}
//这里因为令牌是UserDetails,所以可以调用getUsername,且我们public class JwtUserDto implements UserDetails里面重写了getUsername方法,就是user的getUsername,但是没有getUser方法可以调用,导致获取user里面一些别的数据很难if (authentication.getPrincipal() instanceof UserDetails) {UserDetails userDetails = (UserDetails) authentication.getPrincipal();System.out.println("登陸報錯的系統用戶名"+userDetails);return userDetails.getUsername();}throw new BadRequestException(HttpStatus.UNAUTHORIZED, "找不到当前登录的信息");}/*** 获取系统用户ID* @return 系统用户ID*/public static Long getCurrentUserId() {UserDetails userDetails = getCurrentUser();// 将 Java 对象转换为 JSONObject 对象JSONObject jsonObject = (JSONObject) JSON.toJSON(userDetails);return jsonObject.getJSONObject("user").getLong("id");}/*** 获取当前用户的数据权限* @return /*/public static List<Long> getCurrentUserDataScope(){UserDetails userDetails = getCurrentUser();// 将 Java 对象转换为 JSONObject 对象JSONObject jsonObject = (JSONObject) JSON.toJSON(userDetails);JSONArray jsonArray = jsonObject.getJSONArray("dataScopes");return JSON.parseArray(jsonArray.toJSONString(), Long.class);}/*** 获取当前用户的角色* @return /*/public static List<String> getCurrentUserRole(){UserDetails userDetails = getCurrentUser();// 将 Java 对象转换为 JSONObject 对象JSONObject jsonObject = (JSONObject) JSON.toJSON(userDetails);JSONObject jsonObjectUser =  jsonObject.getJSONObject("user");JSONArray roles = jsonObjectUser.getJSONArray("roles");
//        return JSON.parseArray(roles.toJSONString(), Role.class);return JSON.parseArray(roles.toJSONString(), String.class);}/*** 获取数据权限级别* @return 级别*/public static String getDataScopeType() {List<Long> dataScopes = getCurrentUserDataScope();if(dataScopes.size() != 0){return "";}return DataScopeEnum.ALL.getValue();}
}

类SpringContextHolder

java">package com.njry.utils;import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;/*** @author * @date 2019-01-07*/
@Slf4j
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {private static ApplicationContext applicationContext = null;private static final List<CallBack> CALL_BACKS = new ArrayList<>();private static boolean addCallback = true;/*** 针对 某些初始化方法,在SpringContextHolder 未初始化时 提交回调方法。* 在SpringContextHolder 初始化后,进行回调使用** @param callBack 回调函数*/public synchronized static void addCallBacks(CallBack callBack) {if (addCallback) {SpringContextHolder.CALL_BACKS.add(callBack);} else {log.warn("CallBack:{} 已无法添加!立即执行", callBack.getCallBackName());callBack.executor();}}/*** 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.*/@SuppressWarnings("unchecked")public static <T> T getBean(String name) {assertContextInjected();return (T) applicationContext.getBean(name);}/*** 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.*/public static <T> T getBean(Class<T> requiredType) {assertContextInjected();return applicationContext.getBean(requiredType);}/*** 获取SpringBoot 配置信息** @param property     属性key* @param defaultValue 默认值* @param requiredType 返回类型* @return /*/public static <T> T getProperties(String property, T defaultValue, Class<T> requiredType) {T result = defaultValue;try {result = getBean(Environment.class).getProperty(property, requiredType);} catch (Exception ignored) {}return result;}/*** 获取SpringBoot 配置信息** @param property 属性key* @return /*/public static String getProperties(String property) {return getProperties(property, null, String.class);}/*** 获取SpringBoot 配置信息** @param property     属性key* @param requiredType 返回类型* @return /*/public static <T> T getProperties(String property, Class<T> requiredType) {return getProperties(property, null, requiredType);}/*** 检查ApplicationContext不为空.*/private static void assertContextInjected() {if (applicationContext == null) {throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext" +".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder.");}}/*** 清除SpringContextHolder中的ApplicationContext为Null.*/private static void clearHolder() {log.debug("清除SpringContextHolder中的ApplicationContext:"+ applicationContext);applicationContext = null;}@Overridepublic void destroy() {SpringContextHolder.clearHolder();}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {if (SpringContextHolder.applicationContext != null) {log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext);}SpringContextHolder.applicationContext = applicationContext;if (addCallback) {for (CallBack callBack : SpringContextHolder.CALL_BACKS) {callBack.executor();}CALL_BACKS.clear();}SpringContextHolder.addCallback = false;}/*** 获取 @Service 的所有 bean 名称* @return /*/public static List<String> getAllServiceBeanName() {return new ArrayList<>(Arrays.asList(applicationContext.getBeanNamesForAnnotation(Service.class)));}
}

项目中实际使用(比如下面两个)
在controller层经常要校验权限

java">    @GetMapping(value = "/detail")@Log("查询原子定义管理详情")@ApiOperation("查询原子定义管理详情")@PreAuthorize("@el.check('atomDict:list')")public ResponseEntity<AtomDict> queryAtomDictDetail(AtomDictQueryCriteria criteria){return new ResponseEntity<>(atomDictService.queryAtomDictDetail(criteria),HttpStatus.OK);}@GetMapping@Log("查询原子定义管理")@ApiOperation("查询原子定义管理")
//    @PreAuthorize("@el.check('atomDict:list')")@PreAuthorize("@el.checkRole()")public ResponseEntity<PageResult<AtomDict>> queryAtomDict(AtomDictQueryCriteria criteria, Page<Object> page){return new ResponseEntity<>(atomDictService.queryAll(criteria,page),HttpStatus.OK);}

类AuthorityConfig 校验权限和角色

java">package com.njry.config;import com.njry.utils.SecurityUtils;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;/*** @author wj*/
@Service(value = "el")
public class AuthorityConfig {public Boolean check(String ...permissions){// 获取当前用户的所有权限List<String> elPermissions = SecurityUtils.getCurrentUser().getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());System.out.println("当前用户的权限"+elPermissions);// 判断当前用户的所有权限是否包含接口上定义的权限return elPermissions.contains("admin") || Arrays.stream(permissions).anyMatch(elPermissions::contains);}public Boolean checkRole(){// 获取当前用户的所有角色List<String> currentUserRole = SecurityUtils.getCurrentUserRole();String sbString = "400";//数据库一个角色的idList<String> collect = currentUserRole.stream().filter(c -> c.contains(sbString)).collect(Collectors.toList());
//        UserDetails里面没有获取用户user 的getter方法
//        虽然 class JwtUserDto implements UserDetailsif(collect.size() > 0){return true;}else{// 判断当前用户的所有权限是否包含接口上定义的权限return false;}}
}

http://www.ppmy.cn/news/1467360.html

相关文章

大模型Prompt-Tuning技术进阶

LLM的Prompt-Tuning主流方法 面向超大规模模型的Prompt-Tuning 近两年来&#xff0c;随之Prompt-Tuning技术的发展&#xff0c;有诸多工作发现&#xff0c;对于超过10亿参数量的模型来说&#xff0c;Prompt-Tuning所带来的增益远远高于标准的Fine-tuning&#xff0c;小样本甚至…

centos7安装 hadoop集群

目录 准备集群搭建步骤1. 环境准备三台服务器IP关闭三台服务器的防火墙修改三台服务器的hostname文件修改三台服务器的hosts映射配置三台服务器之间的免密登录三台时间同步设置 2. hadoop安装资源划分3. 开始搭建hadoop集群192.168.83.144 即 hadoop1上的修改解压安装包添加环境…

【好书分享第十三期】AI数据处理实战108招:ChatGPT+Excel+VBA

文章目录 一、内容介绍二、内页插图三、作者简介四、前言/序言五、目录 一、内容介绍 《AI数据处理实战108招&#xff1a;ChatGPTExcelVBA》通过7个专题内容、108个实用技巧&#xff0c;讲解了如何运用ChatGPT结合办公软件Excel和VBA代码实现AI办公智能化、高效化。随书附赠了…

介绍Django Ninja框架

文章目录 安装快速开始特性详解自动文档生成定义请求和响应模型异步支持中间件支持测试客户端 结论 Django Ninja是一个基于Python的快速API开发框架&#xff0c;它结合了Django和FastAPI的优点&#xff0c;提供了简单易用的方式来构建高性能的Web API。 安装 使用以下命令安…

【JavaScript脚本宇宙】优化你的React项目:探索表单库的世界

React表单库解析&#xff1a;特性&#xff0c;使用方法和使用场景 前言 在现代的web开发中&#xff0c;表单是Web应用程序的核心组成部分之一。为了助力开发者更快捷、高效地处理表单状态和验证等问题&#xff0c;本文将介绍六种不同的React表单库&#xff0c;包括它们的特性…

设计模式之过滤器模式FilterPattern(十)

一、过滤器模式 过滤器模式&#xff08;Filter Pattern&#xff09;或标准模式&#xff08;Criteria Pattern&#xff09;是一种设计模式&#xff0c;这种模式允许开发人员使用不同的标准来过滤一组对象&#xff0c;通过逻辑运算以解耦的方式把它们连接起来。这种类型的设计模…

通过LabVIEW提升生产设备自动化水平

现代制造业对生产设备的自动化水平提出了越来越高的要求。使用LabVIEW这一强大的图形化编程环境&#xff0c;可以显著提升生产设备的自动化程度&#xff0c;改善生产效率和产品质量。本文将详细分析如何通过LabVIEW改善生产设备的自动化水平&#xff0c;并提供具体的实施策略与…

Spring系统学习 - Spring入门

什么是Spring&#xff1f; Spring翻译过来就是春天的意思&#xff0c;字面意思&#xff0c;冠以Spring的意思就是想表示使用这个框架&#xff0c;代表程序员的春天来了&#xff0c;实际上就是让开发更加简单方便&#xff0c;实际上Spring确实做到了。 官网地址&#xff1a;ht…