使用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添加完那些东西后…

    浅析C语言中assert的用法(转)

    原文地址&#xff1a;http://www.jb51.net/article/39685.htm 以下是对C语言中assert的使用方法进行了介绍&#xff0c;需要的朋友可以参考下。 assert宏的原型定义在<assert.h>中&#xff0c;其作用是如果它的条件返回错误&#xff0c;则终止程序执行&#xff0c;原型定…

    hihocoder offer收割编程练习赛12 D 寻找最大值

    思路&#xff1a; 可能数据太水了&#xff0c;随便乱搞就过了。 实现&#xff1a; 1 #include <iostream>2 #include <cstdio>3 #include <algorithm>4 using namespace std;5 typedef long long ll;6 7 int a[100005], n;8 9 int main() 10 { 11 int t;…

    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 代码中设置 临时 环境变量

    System.setProperty("hadoop.home.dir", "D:\\software\\software_install\\dev_install\\hadoop-2.4.1"); 转载于:https://www.cnblogs.com/zychengzhiit1/p/6662376.html

    什么是快速开发框架

    什么是快速开发框架 前言 做为一个程序员&#xff0c;在开发的过程中会发现&#xff0c;有框架同无框架&#xff0c;做起事来是完全不同的概念&#xff0c;关系到开发的效率、程序的健壮、性能、团队协作、后续功能维护、扩展......等方方面面的事情。很多朋友在学习搭建自己…

    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…

    C语言程序设计预报作业

    1阅读邹欣老师的博客--师生关系,针对文中的几种师生关系谈谈你的看法&#xff0c;你期望的师生关系是什么样的&#xff1f; 答&#xff1a;我认为文中的师生关系都存在一些缺陷&#xff0c;第一种师生关系是建立在病态关系上的&#xff0c;学生不是植物自然有自己的思想。所以我…

    浅谈23种设计模式

    浅谈23种设计模式 类之间的关联关系&#xff1a;在使用Java、C#和C等编程语言实现关联关系时&#xff0c;通常将一个类作为另一个类的属性。   (1)双向关联&#xff0c;两个类互相为各自的属性&#xff0c;比如顾客类Customer和商品类Product&#xff0c;顾客拥有商品&#x…

    网页布局基础

    1、盒子模型的第一层到第五层&#xff1a; border、padding content、background-image、background-color、margin 2、清除浮动。对受到浮动影响的标签作以下操作&#xff1a; 1、clear: both; 2、clear: right; clear: left; 3、设置宽度width: 100%(或者固定宽度) overflow…

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

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

    浅谈我所见的CSS命名风格

    在两年工作中&#xff0c;总结一下我所见的css命名风格。 1.单一class命名 .header {width: 500px; } .item {text-indent: 20%; } 优点&#xff1a;简单&#xff0c;渲染效率高。 缺点&#xff1a;零散&#xff0c;没有模块化。 2. 后代选择器class命名 .header .item a {font…

    Java规范请求中的数字

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

    ORACLE MOS 翻译

    http://blog.csdn.net/msdnchina/article/details/53174196转载于:https://www.cnblogs.com/zengkefu/p/6665950.html

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

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

    python数列分段_按范围分段的Python数组

    首先&#xff0c;定义你的“极”数第二&#xff0c;根据这些“极”数生成间隔第三&#xff0c;定义尽可能多的列表。在然后&#xff0c;对于每个间隔&#xff0c;扫描列表并在相关列表中添加属于该间隔的项代码&#xff1a;source [1, 4, 7, 9, 2, 10, 5, 8]poles (0,3,6,25)…