使用OAuth2令牌的安全REST服务

1.简介

在本教程中,我们将介绍如何将Spring Security与OAuth结合使用以保护REST服务。 在演示应用程序中,可以使用路径模式( / api / ** )访问服务器上受保护的REST资源,以便基于该路径的请求URL映射到不同的控制器方法。 这意味着 -

  • 路径中没有' / api '的任何REST请求URL都将保持无效 ,因为这些URL与任何控制器映射都不匹配。
  • 完成所需的OAuth2配置后,任何不带令牌作为参数的REST请求URL都将是未授权的

我们配置的另一个路径模式( / oauth / token )将帮助已配置的授权服务器生成访问令牌。 请注意,我们将在此演示应用程序中使用“ 密码授予类型”

在继续实施之前,让我们回顾一下与该授予类型有关的事件。

2.资源所有者密码凭证授予类型

  • 在受信任的应用程序之间使用。
  • 用户(资源所有者)直接与客户端应用程序共享凭据,客户端应用程序在成功验证用户凭据并进一步授权用户访问服务器上的有限资源后,请求授权服务器返回访问令牌。

有用的链接

  • 了解有关其他授权授予类型的更多信息
  • 了解OAuth2令牌认证

3.实施

确保将所需的pom条目正确添加到pom.xml文件中。

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.springframework.samples.service.service</groupId><artifactId>SecureRESTWithOAuth</artifactId><version>0.0.1-SNAPSHOT</version><packaging>war</packaging><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency><!-- Spring dependencies --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>4.2.1.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>4.2.1.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>4.2.1.RELEASE</version></dependency><!-- Jackson JSON Processor --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.4.1</version></dependency><!-- Spring Security Dependencies --><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-core</artifactId><version>3.2.3.RELEASE</version></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-web</artifactId><version>3.2.3.RELEASE</version></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-config</artifactId><version>3.2.3.RELEASE</version></dependency><dependency><groupId>org.springframework.security.oauth</groupId><artifactId>spring-security-oauth2</artifactId><version>1.0.0.RELEASE</version></dependency></dependencies>
</project>

web.xml

更新web.xml文件以加载上下文文件并配置Spring Security过滤器,该过滤器将在处理请求之前重定向身份验证和授权请求。

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"id="WebApp_ID" version="2.5"><display-name>SecureRESTWithOAuth</display-name><servlet><servlet-name>mvc-dispatcher</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>mvc-dispatcher</servlet-name><url-pattern>/*</url-pattern></servlet-mapping><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!-- Loads context files --><context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/mvc-dispatcher-servlet.xml,/WEB-INF/spring-security.xml</param-value></context-param><!-- Spring Security --><filter><filter-name>springSecurityFilterChain</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class></filter><filter-mapping><filter-name>springSecurityFilterChain</filter-name><url-pattern>/*</url-pattern></filter-mapping></web-app>

mvc-dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"><context:component-scan base-package="com.jcombat.controller" /><mvc:annotation-driven /></beans>

由于我们将使用admin JSP文件,因此我们已经为其配置了相应的视图解析器。

现在,让我们在其上下文文件中配置Spring Security OAuth。

spring-security.xml

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:oauth="http://www.springframework.org/schema/security/oauth2"xmlns:context="http://www.springframework.org/schema/context"xmlns:sec="http://www.springframework.org/schema/security" xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd  http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd  http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd "><!-- Default url to get a token from OAuth --><http pattern="/oauth/token" create-session="stateless"authentication-manager-ref="clientAuthenticationManager"xmlns="http://www.springframework.org/schema/security"><intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" /><anonymous enabled="false" /><http-basic entry-point-ref="clientAuthenticationEntryPoint" /><custom-filter ref="clientCredentialsTokenEndpointFilter"after="BASIC_AUTH_FILTER" /><access-denied-handler ref="oauthAccessDeniedHandler" /></http><!-- URLs should be protected and what roles have access to them --><!-- Can define more patterns based on the protected resources hosted on the server --><http pattern="/api/**" create-session="never"entry-point-ref="oauthAuthenticationEntryPoint"access-decision-manager-ref="accessDecisionManager"xmlns="http://www.springframework.org/schema/security"><anonymous enabled="false" /><intercept-url pattern="/api/**" access="ROLE_APP" /><!-- Protect oauth clients with resource ids --><custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" /><access-denied-handler ref="oauthAccessDeniedHandler" /></http><bean id="oauthAuthenticationEntryPoint"class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint"><property name="realmName" value="demo/client" /></bean><bean id="clientAuthenticationEntryPoint"class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint"><property name="realmName" value="demo/client" /><property name="typeName" value="Basic" /></bean><bean id="oauthAccessDeniedHandler"class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" /><bean id="clientCredentialsTokenEndpointFilter"class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter"><property name="authenticationManager" ref="clientAuthenticationManager" /></bean><bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"xmlns="http://www.springframework.org/schema/beans"><constructor-arg><list><bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" /><bean class="org.springframework.security.access.vote.RoleVoter" /><bean class="org.springframework.security.access.vote.AuthenticatedVoter" /></list></constructor-arg></bean><authentication-manager id="clientAuthenticationManager"xmlns="http://www.springframework.org/schema/security"><authentication-provider user-service-ref="clientDetailsUserService" /></authentication-manager><!-- This is simple authentication manager, with a hard-coded username/password combination. We can replace this with a user defined service to fetch user credentials from DB instead --><authentication-manager alias="authenticationManager"xmlns="http://www.springframework.org/schema/security"><authentication-provider><user-service><user name="admin" password="123" authorities="ROLE_APP" /></user-service></authentication-provider></authentication-manager><bean id="clientDetailsUserService"class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService"><constructor-arg ref="clientDetails" /></bean><!-- This defines the token store. We have currently used in-memory token store but we can instead use a user defined one --><bean id="tokenStore"class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" /><!-- If need to store tokens in DB <bean id="tokenStore"class="org.springframework.security.oauth2.provider.token.store.JdbcTokenStore"><constructor-arg ref="jdbcTemplate" /></bean> --><!-- This is where we defined token based configurations, token validity and other things --><bean id="tokenServices"class="org.springframework.security.oauth2.provider.token.DefaultTokenServices"><property name="tokenStore" ref="tokenStore" /><property name="supportRefreshToken" value="true" /><property name="accessTokenValiditySeconds" value="120" /><property name="clientDetailsService" ref="clientDetails" /></bean><bean id="userApprovalHandler"class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler"><property name="tokenServices" ref="tokenServices" /></bean><!-- The server issuing access tokens to the client after successfully authenticating the resource owner and obtaining authorization --><oauth:authorization-serverclient-details-service-ref="clientDetails" token-services-ref="tokenServices"user-approval-handler-ref="userApprovalHandler"><oauth:authorization-code /><oauth:implicit /><oauth:refresh-token /><oauth:client-credentials /><oauth:password /></oauth:authorization-server><!-- Define protected resources hosted by the resource server --><oauth:resource-server id="resourceServerFilter"resource-id="adminProfile" token-services-ref="tokenServices" /><!-- OAuth clients allowed to access the protected resources, can be something like facebook, google if we are sharing any resource with them --><oauth:client-details-service id="clientDetails"><oauth:client client-id="fbApp"authorized-grant-types="password,refresh_token"secret="fbApp" authorities="ROLE_APP" resource-ids="adminProfile" /></oauth:client-details-service><sec:global-method-securitypre-post-annotations="enabled" proxy-target-class="true"><sec:expression-handler ref="oauthExpressionHandler" /></sec:global-method-security><oauth:expression-handler id="oauthExpressionHandler" /><oauth:web-expression-handler id="oauthWebExpressionHandler" /></beans>

我们已经配置了/ oauth / token URL来发布访问和刷新令牌,并且/ api / **映射到服务器上实际受保护的资源。 因此,要访问与模式/ api / **匹配的任何URL,需要将有效令牌与请求一起传递。

身份验证管理器是进行身份验证的容器。 在我们的情况下,身份验证管理器检查–

  • 用户是否通过身份验证。
  • 用户是否请求了正确的客户ID。
  • 如果client-id正确,则该用户是否有权使用它来访问服务器上的管理配置文件。

请参阅以下代码段–

<authentication-manager id="clientAuthenticationManager"xmlns="http://www.springframework.org/schema/security"><authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager><bean id="clientDetailsUserService"class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService"><constructor-arg ref="clientDetails" />
</bean><!-- OAuth clients allowed to access the protected resources, can be something like facebook, google if we are sharing any resource with them -->
<oauth:client-details-service id="clientDetails"><oauth:client client-id="fbApp"authorized-grant-types="password,refresh_token"secret="fbApp" authorities="ROLE_APP" resource-ids="adminProfile" />
</oauth:client-details-service>

用户通过身份验证后, 授权服务器将调用tokenServices并颁发访问令牌。

<oauth:authorization-serverclient-details-service-ref="clientDetails" token-services-ref="tokenServices"user-approval-handler-ref="userApprovalHandler"><oauth:authorization-code /><oauth:implicit /><oauth:refresh-token /><oauth:client-credentials /><oauth:password />
</oauth:authorization-server><bean id="tokenServices"class="org.springframework.security.oauth2.provider.token.DefaultTokenServices"><property name="tokenStore" ref="tokenStore" /><property name="supportRefreshToken" value="true" /><property name="accessTokenValiditySeconds" value="120" /><property name="clientDetailsService" ref="clientDetails" />
</bean><bean id="tokenStore"class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" /><bean id="userApprovalHandler"class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler"><property name="tokenServices" ref="tokenServices" />
</bean>

在指定客户端时,请注意我们指定的授权类型,即password

<oauth:client-details-service id="clientDetails"><oauth:client client-id="fbApp"authorized-grant-types="password,refresh_token"secret="fbApp" authorities="ROLE_APP" resource-ids="adminProfile" />
</oauth:client-details-service&gt

发出访问令牌后,我们便可以访问服务器上受保护的资源,并将其与每个请求一起传递。 最后,让我们看看我们编写的Spring Controller –

EmployeeController.java

package com.jcombat.controller;import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import com.jcombat.bean.Employee;@RestController
@RequestMapping(value = "/api/Employee")
public class EmployeeController {@RequestMapping(value = "/{name}", method = RequestMethod.GET)public Employee process(@PathVariable("name") String name,@RequestParam(value = "empId", required = false, defaultValue = "00000") final String id) {Employee employee = new Employee();employee.setEmpId(id);employee.setName(name);return employee;}
};

4.运行应用程序

要运行该应用程序,让我们首先从授权服务器请求访问令牌-

http:// localhost:8080 / SecureRESTWithOAuth / oauth / token? grant_type =密码和client_id = fbApp& client_secret = fbApp& 用户名 = admin& 密码 = 123

{  "value":"a7718567-6e38-4be3-aa41-382c90e042e0","expiration":1505631027817,"tokenType":"bearer","refreshToken":{  "value":"7792b077-7ae0-427e-8170-8b1440e5fefd","expiration":1508222907814},"scope":[  ],"additionalInformation":{  },"expiresIn":109,"expired":false
}

生成访问令牌后,我们准备将其与服务器上对受保护资源的所有后续请求一起传递。

http:// localhost:8080 / SecureRESTWithOAuth / api / Employee / abhimanyu? access_token = 7792b077-7ae0-427e-8170-8b1440e5fefd

5.下载代码

下载源代码

翻译自: https://www.javacodegeeks.com/2017/09/secure-rest-service-oauth2-tokens.html

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

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

相关文章

java 内联调用深度_Java中内联虚拟方法调用的性能

java 内联调用深度总览 动态编译的好处之一是它能够支持在虚拟方法代码上的广泛方法内联。 内联代码可提高性能时&#xff0c;代码仍必须检查类型&#xff08;以防由于优化而更改了类型&#xff09;或在多个可能的实现之间进行选择。 这导致了问题。 通过接口调用的方法的多个…

组件切换方式(Vue.js)

这里&#xff0c;我用一个注册登录两组件的切换实例来演示&#xff1a; 切换方式一 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8" /><title>独秀不爱秀</title> </head><body><div …

在GWT中序列化/反序列化Json

JSON和GWT 最近&#xff0c; GWT用户小组中进行了有趣的讨论 &#xff0c;涉及在客户端对JSON进行序列化/反序列化的最佳实践。 这篇文章旨在突出其重点。 到目前为止&#xff0c;在GWT中有三种将对象转换为JSON并从客户端转换回JSON的方法&#xff1a; gwt-jackson框架&#…

NOIP模拟测试15「建造城市city(插板法)·轰炸·石头剪刀布」

建造城市 题解 先思考一个简单问题 10个$toot$ 放进5间房屋&#xff0c;每个房屋至少有1个$toot$&#xff0c;方案数 思考&#xff1a;插板法&#xff0c;$10$个$toot$有$9$个缝隙&#xff0c;$5$间房屋转化为$4$个挡板&#xff0c;放在toot缝隙之间得到$C_{9}^{4}$ 10个$toot$…

弹簧和线程:TaskExecutor

在Web应用程序中使用线程并不常见&#xff0c;尤其是当您必须开发长期运行的任务时。 考虑到spring&#xff0c;我们必须格外注意并使用它已经提供的工具&#xff0c;而不是生成我们自己的线程。 我们希望线程由spring管理&#xff0c;因此能够在不产生任何影响的情况下使用应…

数位dp从会打模板到不会打模板

打了几个数位$dp$&#xff0c;发现自己除了会打模板之外没有任何长进&#xff0c;遇到非模板题依然什么都不会 那么接下来这篇文章将介绍如何打模板&#xff08;滑稽&#xff09; 假设我们要处理$l----r$ 采用记忆化搜索的方式&#xff0c;枚举$<r$每一种情况&#xff0c;枚…

javafx简单吗_JavaFX即将推出您附近的Android或iOS设备吗?

javafx简单吗已经有大新闻最近在世界上的JavaFX的关于JavaFX的是许多更多的组件开源&#xff0c;开源的广告在2012 JavaOne大会 。 在2月的开放源代码更新中 &#xff0c; Richard Bair编写了一份JavaFX项目表&#xff0c;该表在撰写本文时&#xff08;2013年2月11日&#xff0…

【webrtc】webrtc的rtp重传代码分析

pgm不太能用&#xff0c;没有想象中的可靠&#xff0c;重传机制貌似仍然使用组播重传&#xff0c;丢包率80%的网络感觉没啥改进&#xff0c;如果有所好转延迟估计也是个不小的问题。 后听说rtp也有nack机制&#xff0c;webrtc基于rtp实现了重传在一定程度上保证可靠性。 在各路…

了解java.nio.file.Path – 1

介绍 Java的最后几个发行版本&#xff0c;即Java 7&#xff0c;Java 8和即将到来的Java 9&#xff0c;具有许多功能&#xff0c;这些功能使Java开发人员的生活更加轻松。 &#xff08;我知道Java 9会使它变得更困难&#xff0c;但是只有在您采用新的范例时才可以。之后&#xf…

socket-01

对于所有的Web应用&#xff0c;本质上其实就是一个socket服务端&#xff0c;用户的浏览器其实就是一个socket客户端 转载于:https://www.cnblogs.com/yanhuaqiang/p/11329925.html

ActionScript3学习笔记2-包

在 ActionScript 3.0 中&#xff0c;包是用命名空间实现的&#xff0c;但包和命名空间并不同义。在声明包时&#xff0c; 可以隐式创建一个特殊类型的命名空间并保证它在编译时是已知的。显式创建的命名空间在 编译时不必是已知的。 下面的示例使用 package 指令来创建一个包含…

grep v grep_使用grep4j轻松测试分布式组件上的SLA

grep v grep因此&#xff0c;您的分布式体系结构如下图所示&#xff0c;您刚刚从企业那里收到了一项要求&#xff0c;以确保生产者发送并随后传输到下游系统&#xff08;消费者&#xff09;的消息的SLA必须快且永远不会慢于此。 400毫秒。 要求说&#xff1a; 从生产者发送到…

得到指定进程所有窗口。显示 影藏 置顶。

这里使用一个外挂程序测试&#xff0c;因为外挂程序没有做功能限制的处理 只是做了 窗口影藏。 全局变量 HWND hwnd[100]{0};int number0;DWORD Tpid0; 局部变量 char username[1028]; 先找到进程ID 1 HWND SelectPor() 2 { 3 bool isYesfalse; 4 string porcessName&q…

jquery部分方法

offset([coordinates]) 概述&#xff1a;获取匹配元素在当前视口的相对偏移。返回的对象包含两个整型属性&#xff1a;top 和 left。此方法只对可见元素有效。 比如&#xff0c;获取第二段的偏移&#xff1a; HTML 代码: <p>Hello</p><p>2nd Paragraph</p…

JUnit 5扩展模型的生命周期

JUnit5最终版本即将来临 &#xff08;当前是M4&#xff09;&#xff0c;我已经开始研究如何编写扩展。 在JUnit5中 &#xff0c;您没有使用Runners &#xff0c; Rules &#xff0c; ClassRules等&#xff0c;而是只有一个Extension API来实现自己的扩展。 JUnit5提供了多个接…

让IE6、IE7、IE8支持CSS3

我们都知道IE6&#xff0c;7并不支持CSS3的属性&#xff0c;IE8也不能很好的支持CSS3。但是有一个小脚本能够做到&#xff0c;它可以让IE支持 CSS3&#xff0c;包括&#xff1a;border-radius (rounded), box-shadow ( shadow), text-shadow等…… 如果你需要一个支持CSS3 的bo…

NOIP模拟测试16「Drink·blue·weed」

话说这次考试 Drink 非常棒的一道卡常练习题&#xff0c;适合练习卡常 真的很棒 前置卡常知识 1.char要比int快 char是最快的 输出putchar&#xff0c;输入getchar 在这个题快了7000豪 2.read 快读非常棒&#xff0c;让你变得更快&#xff0c;fread更棒&#xff0c;fread会爆炸…

Spring Boot Web Slice测试–示例

春天开机推出 测试切片而回&#xff0c;它已经采取了一些时间来解决它我的头&#xff0c;并探讨一些细微的差别。 背景 使用此功能的主要原因是减少样板。 考虑一个看起来像这样的控制器&#xff0c;仅适用于使用Kotlin编写的各种控制器。 RestController RequestMapping(&qu…

DECODE函数

DECODE函数相当于一条件语句(IF),它将输入数值与函数中的参数列表相比较&#xff0c;根据输入值返回一个对应值。函数的参数列表是由若干数值及其对应结果值组成的若干序偶形式。当然&#xff0c;如果未能与任何一个实参序偶匹配成功&#xff0c;则函数也有默认的返回值。区别于…

多线程练习

写两个线程&#xff0c;其中一个线程打印1-52&#xff0c;另一个线程打印A-Z&#xff0c;打印顺序应该是12A34B56C......5152Z。 该习题需要用到多线程通信的知识。 思路分析&#xff1a; 把打印数字的线程称为线程N&#xff0c;打印字母的线程称为线程L. 1.线程N完成打印后&am…