很久以前,我从事的项目具有很强大的功能。 有两个角色:用户和主管。 主管可以以任何方式更改系统中的任何文档,而用户则更受工作流约束的限制。 当普通用户对当前正在编辑和存储在HTTP会话中的文档有疑问时,主管可以介入,切换到特殊的主管模式并绕过所有约束。 完全自由。 相同的计算机,相同的键盘,相同的HTTP会话。 通过输入秘密密码,只有管理员可以设置的特殊标志。 主管完成后,他或她可以清除该标志并再次启用常规约束。

此功能运行良好,但实施效果不佳。 每个单个输入字段的可用性取决于该超级用户模式标志。 使用isSupervisorMode()检查在数十个地方污染了业务方法。 请记住,如果管理员只是使用常规凭据登录,则此模式是隐式的,因此安全约束基本上是重复的。

当我们的应用程序可以高度自定义并具有大量安全角色时,就会出现另一个有趣的用例。 迟早您将面临异常(确定, 错误 ),您无法复制具有不同权限的异常。 能够以该特定用户身份登录并环顾四周可能是一个很大的胜利。 当然,您不知道用户的密码( 不是吗? )。 类似UNIX的系统找到了解决此问题的方法: su切换用户 )和sudo命令。 出乎意料的是, Spring Security附带了内置的SwitchUserFilter ,它在原则上模仿Web应用程序中的su 。 试一试吧!

您需要声明自定义过滤器:

<bean id="switchUserProcessingFilter"class="org.springframework.security.web.authentication.switchuser.SwitchUserFilter"><property name="userDetailsService" ref="userDetailsService"/><property name="targetUrl" value="/"/>
</b:bean>

并在<http>配置中指向它:

<http auto-config="true" use-expressions="true"><custom-filter position="SWITCH_USER_FILTER" ref="switchUserProcessingFilter" /><intercept-url pattern="/j_spring_security_switch_user" access="hasRole('ROLE_SUPERVISOR')"/>...

而已! 请注意,我保护了/j_spring_security_switch_user URL模式。 您猜对了,这就是您以其他用户身份登录的方式,因此我们希望此资源得到良好的保护。 默认情况下,使用j_username参数名称。 将上述更改应用于您的Web应用程序并以具有ROLE_SUPERVISOR的用户ROLE_SUPERVISOR登录后,只需浏览以下内容即可:

/j_spring_security_switch_user?j_username=bob

假设存在这样的用户,您将自动以bob身份登录。 此处不需要密码。 模拟完他后,浏览至/j_spring_security_exit_user将还原您以前的凭据。 当然,所有这些URL是可配置的。 参考文档中未记录SwitchUserFilter ,但谨慎使用时它是非常有用的工具。

确实具有强大的力量…… 。 像任何其他任意用户一样,甚至让最受信任的用户登录也具有很大的风险。 想象一下在Facebook上的这种功能,这是不可能的! ( 很好…… )因此,跟踪和审核成为一项主要要求。

我通常首先要做的是在Spring Security过滤器之后添加一个小的servlet过滤器,该过滤器将用户名添加到MDC :

import org.slf4j.MDC;public class UserNameFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();final String userName = authentication.getName();final String fullName = userName + (realName != null ? " (" + realName + ")" : "");MDC.put("user", fullName);try {chain.doFilter(request, response);} finally {MDC.remove("user");}}private String findSwitchedUser(Authentication authentication) {for (GrantedAuthority auth : authentication.getAuthorities()) {if (auth instanceof SwitchUserGrantedAuthority) {return ((SwitchUserGrantedAuthority)auth).getSource().getName();}}return null;}//...
}

只要记住 Spring Security 之后将其添加到web.xml 。 此时,您可以在logback.xml引用"user"键:

<pattern>%d{HH:mm:ss.SSS} | %-5level | %X{user} | %thread | %logger{1} | %m%n%rEx</pattern>

看到%X{user}代码段? 每次登录的用户在系统中执行某些触发日志语句的操作时,都会看到该用户的名称:

21:56:55.074 | DEBUG | alice | http-bio-8080-exec-9 | ...
//...
21:56:57.314 | DEBUG | bob (alice) | http-bio-8080-exec-3 | ...

第二个日志语句很有趣。 如果您查看上面的findSwitchedUser()调用,很明显,作为管理员的alice切换到用户bob ,现在代表他浏览。

有时您需要更强大的审核系统。 幸运的是,Spring框架具有内置的事件基础结构,我们可以利用当有人切换用户并退出此模式时发送的AuthenticationSwitchUserEvent

@Service
public class SwitchUserListenerimplements ApplicationListener<AuthenticationSwitchUserEvent> {private static final Logger log = LoggerFactory.getLogger(SwitchUserListener.class);@Overridepublic void onApplicationEvent(AuthenticationSwitchUserEvent event) {log.info("User switch from {} to {}",event.getAuthentication().getName(),event.getTargetUser().getUsername());}
}

当然,您可以使用所需的任何业务逻辑来替换简单的日志记录,例如,将此类事件存储在数据库中或向安全员发送电子邮件。

因此,我们知道如何以其他用户身份登录一段时间,然后退出这种模式。 但是,如果我们需要“ sudo ”,即代表其他用户仅发出一个HTTP请求,该怎么办? 当然,我们可以切换到该用户,运行该请求,然后退出。 但这似乎太繁重且麻烦。 当客户端程序访问我们的API并希望以其他用户身份查看数据时(考虑测试复杂的ACL),可能会弹出这样的要求。

添加自定义HTTP标头以表示这样的特殊模拟请求听起来很合理。 假设客户端已经在进行身份验证(例如使用JSESSIONID cookie),则该功能仅在一个请求期间有效。 不幸的是,Spring Security不支持此功能,但是很容易在SwitchUserFilter之上SwitchUserFilter

public class SwitchUserOnceFilter extends SwitchUserFilter {@Overridepublic void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) req;final String switchUserHeader = request.getHeader("X-Switch-User-Once");if (switchUserHeader != null) {trySwitchingUserForThisRequest(chain, request, res, switchUserHeader);} else {super.doFilter(req, res, chain);}}private void trySwitchingUserForThisRequest(FilterChain chain, HttpServletRequest request, ServletResponse response, String switchUserHeader) throws IOException, ServletException {try {proceedWithSwitchedUser(chain, request, response, switchUserHeader);} catch (AuthenticationException e) {throw Throwables.propagate(e);}}private void proceedWithSwitchedUser(FilterChain chain, HttpServletRequest request, ServletResponse response, String switchUserHeader) throws IOException, ServletException {final Authentication targetUser = attemptSwitchUser(new SwitchUserRequest(request, switchUserHeader));SecurityContextHolder.getContext().setAuthentication(targetUser);try {chain.doFilter(request, response);} finally {final Authentication originalUser = attemptExitUser(request);SecurityContextHolder.getContext().setAuthentication(originalUser);}}}

与原始SwitchUserFilter的唯一区别是,如果存在"X-Switch-User-Once" ,则将凭据切换到由此标头的值表示的用户-但是仅在一个HTTP请求期间。 SwitchUserFilter假定要切换到的用户名在j_username参数下,因此我不得不使用SwitchUserRequest包装器作弊:

private class SwitchUserRequest extends HttpServletRequestWrapper {private final String switchUserHeader;public SwitchUserRequest(HttpServletRequest request, String switchUserHeader) {super(request);this.switchUserHeader = switchUserHeader;}@Overridepublic String getParameter(String name) {switch (name) {case SPRING_SECURITY_SWITCH_USERNAME_KEY:return switchUserHeader;default:return super.getParameter(name);}}
}

我们的自定义“ sudo ”就位了! 您可以使用curl进行测试:

$ curl localhost:8080/books/rest/book \-H "X-Switch-User-Once: bob" \-b "JSESSIONID=..."

当然,如果没有JSESSIONID cookie,系统将不允许我们进入。我们必须首先登录,并具有访问sudo功能的特殊特权。 切换用户是一个方便且功能强大的工具。 如果您想在实践中尝试,请查看GitHub上的工作示例 。

参考: Java和社区博客上我们JCG合作伙伴 Tomasz Nurkiewicz提供的Spring Security应用程序中的su和sudo 。

翻译自: https://www.javacodegeeks.com/2013/07/su-and-sudo-in-spring-security-applications.html

Spring Security应用程序中的su和sudo相关推荐

  1. sudo su su_Spring Security应用程序中的su和sudo

    sudo su su 很久以前,我从事的项目具有很强大的功能. 有两个角色:用户和主管. 主管可以以任何方式更改系统中的任何文档,而用户则更受工作流约束的限制. 当普通用户对当前正在编辑并存储在HTT ...

  2. Spring MVC,Thymeleaf,Spring Security应用程序中的CSRF保护

    跨站点请求伪造(CSRF)是一种攻击,它迫使最终用户在当前已通过身份验证的Web应用程序上执行不需要的操作. 如果您使用Spring Security 3.2及更高版本,在Spring MVC / T ...

  3. kafka 启动_「首席看Event Hub」如何在您的Spring启动应用程序中使用Kafka

    在体系结构规划期间选择正确的消息传递系统始终是一个挑战,但这是需要确定的最重要的考虑因素之一.作为一名开发人员,我每天都要编写需要服务大量用户并实时处理大量数据的应用程序. 通常,我将Java与Spr ...

  4. 如何在Spring Boot应用程序中使用配置文件

    你好朋友, 在本教程中,我们将学习如何在Spring Boot应用程序中使用配置文件. 我们将在本教程中讨论以下几点: 1.什么是Spring Boot Profile,为什么我们需要分析 2.如何使 ...

  5. 在使用Gradle构建的Spring Boot应用程序中覆盖Spring Framework版本

    如果要使用或仅通过Spring Boot检查Spring的最新版本,但当前的Spring Boot版本取决于旧的Spring版本,则需要稍微调整Gradle构建配置. 例如,在撰写本文时,Spring ...

  6. 在Spring Boot应用程序中测试邮件代码

    在构建Spring Boot应用程序时,您可能会需要添加邮件配置. 实际上,在Spring Boot中配置邮件与在Spring Bootless应用程序中配置邮件没有太大区别. 但是,如何测试邮件配置 ...

  7. 在Spring MVC应用程序中使用Bean Validation 1.1获得更好的错误消息

    在许多新功能中, Bean Validation 1.1引入了使用统一表达式语言(EL)表达式的错误消息插值. 这允许基于条件逻辑来定义错误消息,还可以启用高级格式化选项 . 添加到Spring MV ...

  8. Spring MVC应用程序中的Thymeleaf模板布局,无扩展

    在使用JSP / JSTL和Apache Tiles几年之后,我开始为我的Spring MVC应用程序发现Thymeleaf. Thymeleaf是一个非常出色的视图引擎,尽管目前缺乏良好的Intel ...

  9. java ldap操作实例_Java Spring Security示例教程中的2种设置LDAP Active Directory身份验证的方法...

    java ldap操作实例 LDAP身份验证是世界上最流行的企业应用程序身份验证机制之一,而Active Directory (Microsoft为Windows提供的LDAP实现)是另一种广泛使用的 ...

最新文章

  1. 系统设计面试题思路综述
  2. MongoDB基本命令总结
  3. POJ - 3436 ACM Computer Factory(最大流+输出残余网络)
  4. gRPC in ASP.NET Core 3.0 -- 前言
  5. 【百度地图API】如何制作一张魔兽地图!!——CS地图也可以,哈哈哈
  6. jquery输入框按下回车提交表单
  7. cpu怎么超频_小白秒变高手 Intel酷睿CPU一键超频就是这么简单
  8. 打开CAD图纸转换成dwf格式的文件
  9. STM32驱动WS2811
  10. java 前后端分离
  11. Java解决高并发下商品库存更新
  12. 谷歌学术搜索 简易PDF爬虫
  13. 解除百度云下载限制速度(谷歌浏览器)
  14. 5 月计算机语言排行,TIOBE 5月编程语言排行榜
  15. Markdown 插入图片技巧
  16. 算法竞赛进阶指南0x10练习7:Corral the Cows
  17. 【论文】AMC:AutoML用于移动设备上的模型压缩和加速
  18. Java中的isnan函数_Java Float类isNaN()方法与示例
  19. 消息服务MNS和消息队列ONS产品对比
  20. Python大数据分析与应用—2020年中国高校毕业生薪酬指数排名

热门文章

  1. python参数_python参数的介绍
  2. java 8 Lambda 表达式(副作用)
  3. (转)ThreadPoolExecutor最佳实践--如何选择队列
  4. 牛客网JAVA专项联系共899题--个人记录学习经历
  5. 空调吸气和排气_吸气剂和二传手被认为有害
  6. java使用缓冲区读取文件_在Java中使用Google的协议缓冲区
  7. java 指令重拍_我发现我的Java重拍了!
  8. Java面试准备:15个Java面试问题
  9. activemq主从配置_使用ActiveMQ –具有故障转移协议的“主/从”配置
  10. 具有ELK的APIGEE API网关日志管理(Elastic Search,Logstash和Kibana)