使用API​​身份验证的Spring Security

背景

尽管有许多博客文章详细介绍了如何使用Spring Security,但是当问题域位于标准LDAP或数据库身份验证之外时,我仍然经常发现配置挑战。 在本文中,我将介绍一些针对Spring Security的简单自定义,使其能够与基于REST的API调用一起使用。 具体来说,用例是您拥有一个API服务,该服务将返回包含SHA-256密码哈希的用户对象。

设定

运行此样本的先决条件是Git和Maven,以及您选择的IDE(已通过Eclipse和IntelliJ进行了测试)。

可以在以下位置找到源代码: https : //github.com/dajevu/Spring3SecurityUsingAPI 。 拉下代码后,执行以下步骤:

  1. 在终端窗口中,cd到位于源代码所在根目录下的Shared目录。
  2. 发出命令mvn clean install。 这将构建Shared子项目,并将jar安装到本地mvn存储库中。
  3. 在Eclipse或IntelliJ中,将项目导入为Maven项目。 在Eclipse中,这将导致创建3个项目:Shared,SpringWebApp和RestfulAPI。 在IntelliJ中,这将表示为子项目。 编译过程完成后,不应有任何错误。
  4. 将目录更改为RestfulAPI。 然后,发出命令mvn jetty:run以运行API webapp。 然后,您可以发出以下URL,该URL将带回以JSON表示的User对象:http:// localhost:9090 / RestfulAPI / api / v1 / user / john
  5. 打开一个新的终端窗口,cd到位于项目根目录下的SpringWebApp目录。 发出命令mvn jetty:run。 这将启动一个包含Spring Security的标准Spring Webapp。 您可以在以下位置访问单个HTML页面:http:// localhost:8080 / SpringWebApp /。 单击“登录”链接后,使用用户名john和密码doe登录。 您应该被重定向到Hello Admin页面。

    为了演示该解决方案,使用了三个Maven模块,如下所示:

    • SpringWebApp 。 这是一个典型的Spring Webapp,仅提供一个JSP页面。 页面的内容将取决于用户当前是否登录。 首次访问该页面时,将显示一个Login链接,该链接将其定向到内置的Spring Security登录表单。 当他们尝试登录时, R ESTEasy客户端用于调用API服务(如下所述),该服务返回一个JSON字符串,该字符串通过RESTEasy客户端转换为Java对象。 以下各节讨论了如何配置Spring Security的详细信息。
    • RestfulAPI 。 提供JSON请求的API服务。 它是使用RESTEasy(JAX-RS实现)配置的,下一节将对其进行详细描述。
    • 共享的 。 它包含其他两个项目之间共享的一些Java类。 具体来说,用户对象DTO和RESTEasy代理定义(由于RESTEasy客户端也可以使用它,因此已共享)。

    RestfulAPI解剖

    API Webapp是使用RESTEasy的Spring实现配置的。 RESTEasy文档非常详尽,因此我将不对其设置进行详细说明。 定义了一个API调用(在Shared项目的UserProxy中),该调用返回静态JSON字符串。 API的代理(或接口)定义如下:

    Resteasy API代理

    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    @Path(UserProxy.Urls.BASE_URL)
    public interface UserProxy {public interface Urls {public static final String BASE_URL = "/api/v1";public static final String USER = "/user/{username}";}@GET@Produces( { MediaType.APPLICATION_JSON })@Path(UserProxy.Urls.USER)public User getUserByUsername(@PathParam("username") String username);
    }

    对于那些熟悉JAX-RS的人来说,您将可以轻松地遵循此配置。 它定义了一个API URI,它将响应发送到/ api / v1 / user / {username}的URL路径的请求,其中{username}被替换为实际的用户名值。 该服务的实现仅返回一个静态响应,如下所示:

    关于唯一复杂的事情是使用用户密码的SHA-256哈希。 很快我们将看到Spring Security如何解释这一点。 访问URL时,将返回以下JSON字符串:

    该Webapp的web.xml包含用于服务于RESTEasy请求的设置配置,因此,如果您好奇的话,请看一下。

    SpringWebApp解剖

    现在我们可以看一下Spring Security的配置。 项目的web.xml文件将其配置为Spring应用程序,并将文件applicationContext-security.xml指定为初始Spring配置文件。 让我们仔细看一下这个文件,因为这是大多数魔术发生的地方:
    让我们遍历每个行号以描述其功能。 第3至5行指示Spring在com.acme目录中查找Spring支持的类,并且将支持Spring批注。 第7行用于加载application.properties文件中指定的属性(用于指定API主机)。 第9至11行为该应用程序启用Spring Security。 通常,作为http的子元素,您将指定使用角色来保护哪些页面,但是为了使本示例简单起见,未对其进行配置。

    第13-17行是基于Spring Security的自定义开始的地方。 我们通过其bean ref定义了一个名为userDetailsS​​rv的自定义身份验证提供程序。 该bean通过自定义类com.acme.security.UserDetailsS​​ervice实现(第19行)。 让我们仔细看一下这个类:

    如您所见,此类实现了Spring接口org.springframework.security.core.userdetails.UserDetailsS​​ervice。 这需要覆盖方法loadUserByUsername。 此方法负责从身份验证提供者/源中检索用户。 返回的用户(或者,如果找不到匹配的用户,则抛出UsernameNotFoundException-第28行)必须包含密码属性,以便Spring Security与表单中提供的内容进行比较。 如前所述,在这种情况下,密码以SHA-256哈希值返回。

    在我们的API实现中,使用API​​Helper类提取用户查找,我们将在后面介绍。 然后,将返回的API数据填充到名为UserDetails的自定义类中。 这将使用相同的名称实现Spring接口。 该接口需要getUsername()和getPassword()方法的具体实现。 Spring将在Security的下一个处理步骤中调用这些值,以将这些值与Web表单中记录的值进行比较。

    Spring如何将SHA-256中返回的密码与表单密码值进行比较。 如果回头看一下XML配置,它包含以下设置:
    注意passwordEncoder -该参考指向Spring类ShaPasswordEncoder。 此类将计算通过Web表单提供的密码的SHA-256密码,然后Spring会将计算出的值与我们通过API返回的值进行比较。

    让我们通过看一下APIHelper类来解决这个问题:

    第8和9行的第一件事是注入API.host属性。 您还记得,这是在application.properties文件中设置的。 这标识了要在其中发布API调用的主机(因为它在本地运行,所以指定了localhost)。 第17至20行使用RESTEasy客户端机制之一发布JSON RESTful调用(RESTEasy也具有所谓的客户端代理实现,它更易于使用/代码更少,但没有提供太多的低级控制)。 然后,通过第26行的Jackson方式,将来自API的结果响应从JSON转换为User Java对象。然后将该Java对象返回给UserDetails服务。

    总结/总结

    如您所见,定制Spring Security以针对API调用(或实际上是任何外部服务)进行身份验证所涉及的实际工作非常简单。 只需要实现几个类,但是尝试第一次弄清楚这一点可能很棘手。 因此,之所以我包括完整的端到端示例。

    参考:来自Jeff's SOA Ruminations博客的JCG合作伙伴 Jeff Davis 使用API​​身份验证的Spring Security 。


    翻译自: https://www.javacodegeeks.com/2012/10/spring-security-using-api-authentication.html

    本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/371168.shtml

    如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

    相关文章

    java nlpir_4-NLPIR汉语分词系统-JAVA

    好吧,之前用的是旧版的,现在出了个新版的,优先选择用新版的哈。从官网下载相应的开发包,然后主要需要找到这几个东西添加到项目工程里面,1.Data文件夹 2.NLPIR_JNI.DLL 3.NLPIR.jar 4.nlpir.properties添加完那些东西后…

    vue error:The template root requires exactly one element.

    error:[vue/valid-template-root] The template root requires exactly one element. 原因&#xff1a; 因为vue的模版中只有能一个根节点&#xff0c;所以在<template>中插入第二个元素就会报错 解决方案&#xff1a; 将<template>中的元素先用一个<div>…

    测试驱动陷阱,第2部分

    单元测试中单元的故事 在本文的上半部分 &#xff0c;您可能会看到一些不好但很流行的测试示例。 但是我不是一个专业评论家&#xff08;也被称为“巨魔”或“仇恨者”&#xff09;&#xff0c;没有任何建设性的话就抱怨。 多年的TDD教给我的不仅仅是事情会变得多么糟糕。 有许…

    java 代码 设置环境变量_Java 配置环境变量教程

    【声明】欢迎转载&#xff0c;但请保留文章原始出处→_→【正文】1、安装JDK开发环境开始安装JDK&#xff1a;修改安装目录如下&#xff1a;确定之后&#xff0c;单击“下一步”。注&#xff1a;当提示安装JRE时&#xff0c;可以选择不要安装。2、配置环境变量&#xff1a;对于…

    组合数据类型练习,英文词频统计实例上(2017.9.22)

    字典实例&#xff1a;建立学生学号成绩字典&#xff0c;做增删改查遍历操作。 sno[33号,34号,35号,36号] grade[100,90,80,120] d{33号:100,34号:90,35号:80,36号:120} print(d) print(每个学号对应分数:,d.items()) print(弹出35号的分数:,d.pop(35号)) print(获取学号:,d.key…

    java中的math.abs_Java.math.BigDecimal.abs()方法

    全屏Java.math.BigDecimal.abs()方法java.math.BigDecimal.abs()返回一个BigDecimal&#xff0c;其值是此BigDecimal的绝对值&#xff0c;其标度是this.scale()。声明以下是java.math.BigDecimal.abs()方法的声明public BigDecimal abs()参数NA返回值此方法返回的名为value&…

    我需要多少内存

    什么是保留堆&#xff1f; 我需要多少内存&#xff1f; 在构建解决方案&#xff0c;创建数据结构或选择算法时&#xff0c;您可能会问自己&#xff08;或其他人&#xff09;这个问题。 如果此图包含1,000,000条边并且我使用HashMap进行存储&#xff0c;此图是否适合我的3G堆&am…

    mysql与串口通信_虚拟机串口与主机串口通信·小程序(下)

    上次说到的&#xff0c;不能做到实时通信。那么开两个进程就可以了&#xff0c;一个用来监听是否有消息传来&#xff0c;一个用来等待用户输入。那么&#xff0c;先来复习一下进程的相关概念。进程结构linux中进程包含PCB(进程控制块)、程序以及程序所操纵的数据结构集&#xf…

    Java规范请求中的数字

    你们都了解Java社区流程 &#xff08;JCP&#xff09;&#xff0c;不是吗&#xff1f; JCP是为Java技术开发标准技术规范的机制。 任何人都可以注册该站点并参与对Java规范请求&#xff08;JSR&#xff09;的审查和提供反馈&#xff0c;并且任何人都可以注册成为JCP成员&#x…

    自从我这样撸代码以后,公司网页的浏览量提高了107%!

    欢迎大家前往腾讯云 社区&#xff0c;获取更多腾讯海量技术实践干货哦~ 本文由腾讯IVWEB团队发表于云 社区专栏 作者&#xff1a;yangchunwen HTTP协议是前端性能乃至安全中一个非常重要的话题&#xff0c;最近在看《web性能权威指南(High Performance Browser Networking)》&a…

    立面设计模式–设计观点

    在上一篇文章中&#xff0c;我们描述了适配器设计模式 。 在今天的文章中&#xff0c;我们将展示另一种类似的“四结构帮派”模式 。 顾名思义&#xff0c;结构模式用于从许多不同的对象形成更大的对象结构。 外观模式就是这样一种模式&#xff0c;它为系统内的一组接口提供了简…

    Java第三次作业 1502 马 帅

    《Java技术》第三次作业 &#xff08;一&#xff09;学习总结 1.书中对面向对象封装性的定义为&#xff1a;指把对象的属性和行为看成一个密不可分的整体&#xff0c;把不需要让外界知道的信息隐蔽起来。简单来说&#xff0c;就是定义的一些对象&#xff0c;只有在本类中才可以…

    sass运算

    sass具有运算的特性&#xff0c;可以对数值型的Value(如&#xff1a;数字、颜色、变量等)进行加减乘除四则运算。 请注意运算符前后请留一个空格&#xff0c;不然会出错。 scss.style css.style 本文转载于:猿2048https://www.mk2048.com/blog/blog.php?idiij12j&titles…

    JavaOne 2012:NetBeans.Next –未来路线图

    我从Continental Ballroom 4和一个NetBeans主题&#xff08; 项目Easel &#xff09;到Continental Ballroom 5&#xff0c;走了必要的几个步骤&#xff0c;以查看另一个面向NetBeans的演示文稿&#xff1a;“ NetBeans.Next –未来路线图”。 Ashwin Rao发起了“羽毛之鸟”&am…

    C#复习正则表达式

    由于前段时间为了写工具学的太J8粗糙 加上最近一段时间太浮躁 所以静下心来复习 一遍以前学的很弱的一些地方1 委托 public delegate double weituo(double a, double b);public static double test1(double a,double b){return a * b;}public static double test2(double a,…

    在vue中安装使用vux

    最近因为的工作的原因在弄vue&#xff0c;从后端弄到前端之前一直用js&#xff0c;现在第一次接触vue感觉还挺有意思的&#xff0c;就是自己太菜了&#xff0c;这个脑子呀。。。。不太够用。。。。。页面设计用了一个叫vux的东西&#xff0c;vux可以提供一些组件&#xff0c;用…

    Zabbix全方位告警接入-电话/微信/短信都支持

    http://www.cnblogs.com/baidu-gaojing/p/5128035.html 百度告警平台地址&#xff1a; http://gaojing.baidu.com 联系我们&#xff1a; 邮箱&#xff1a;gaojingbaidu.com 电话&#xff1a;13924600771 QQ群&#xff1a;183806029 对于使用zabbix的用户&#xff0c;要接入百度…

    Spring MVC定制用户登录注销实现示例

    这篇文章描述了如何实现对Spring MVC Web应用程序的自定义用户访问&#xff08;登录注销&#xff09;。 作为前提&#xff0c;建议读者阅读这篇文章 &#xff0c;其中介绍了一些Spring Security概念。 该代码示例可从Spring-MVC-Login-Logout目录中的Github获得。 它从带有注释…

    HTML5与CSS3权威指南笔记案例1

    第1章 <!DOCTYPE html> <meta charset "UTF-8"> <title> Search </title> <form> <p><label>Search&#xff1a;<input name"search" autofocus></label> </p> </form> <!DOCTYPE&…

    java循环的概念_Java数据结构之循环队列简单定义与用法示例

    本文实例讲述了Java数据结构之循环队列简单定义与用法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;一、概述&#xff1a;1、原理&#xff1a;与普通队列的区别在于循环队列添加数据时&#xff0c;如果其有效数据end maxSize - 1(最大空间)的话&#xff0c;end指针…