security with restful
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html
内部邀请码:C8E245J (不写邀请码,没有现金送)
国内私募机构九鼎控股打造,九鼎投资是在全国股份转让系统挂牌的公众公司,股票代码为430719,为“中国PE第一股”,市值超1000亿元。
------------------------------------------------------------------------------------------------------------------------------------------------------------------
http://marcin-michalski.pl/
Webservice (Spring Security + JavaScript + AJAX)
Recently I was playing a little bit with different types of authentications. As you know we distinguish Basic, Digest and Form-Based authentications (more about that here). When we are working with web application it is usually sufficient to use either of them but the problem arises when we need to work with RESTfull system where there is no login page or any browser pop-up window to enter the credentials.
One of the solutions would be to store credentials as a plain text somewhere in the request, however it is not very secure way and I would not recommend this solution. It is better to use Digest Authentication (RFC 2617). With this approach we always send data in encrypted format. Spring Security gives us most of that functionality out of the box however it does not support pure JavaScript clients. That is why I had to do some refinements in order to make it work.
Below I’m presenting step by step what needs to be done in order to configure Spring Security and jQuery/Ajax client that calls secured resource.
You may also download whole code from our github repository.
Setting Spring Contexts
Main Application context file – web-application-context.xml:
| XML | | copy code | | ? |
| 01 |
<?xml version="1.0" encoding="UTF-8"?> |
| 02 |
<beans xmlns="http://www.springframework.org/schema/beans" |
| 03 |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| 04 |
xmlns:context="http://www.springframework.org/schema/context" |
| 05 |
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd |
| 06 |
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"> |
| 07 |
|
| 08 |
<import resource="security.xml"/> |
| 09 |
<import resource="security-inmemory-auth-provider.xml"/> |
| 10 |
|
| 11 |
</beans> |
Security configuration context – security.xml
| XML | | copy code | | ? |
| 01 |
<?xml version="1.0" encoding="UTF-8"?> |
| 02 |
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| 03 |
xmlns:security="http://www.springframework.org/schema/security" |
| 04 |
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd |
| 05 |
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> |
| 06 |
|
| 07 |
<security:global-method-security secured-annotations="enabled" pre-post-annotations="enabled"/> |
| 08 |
|
| 09 |
<security:http pattern="/resources/**" security="none"/> |
| 10 |
<security:http pattern="/guest/**" security="none"/> |
| 11 |
|
| 12 |
<security:http |
| 13 |
entry-point-ref="digestEntryPoint" > |
| 14 |
<security:custom-filter ref="digestFilter" position="BASIC_AUTH_FILTER"/> |
| 15 |
<security:intercept-url pattern="/user/**" access="ROLE_USER"/> |
| 16 |
</security:http> |
| 17 |
|
| 18 |
|
| 19 |
<bean id="digestFilter" class="org.springframework.security.web.authentication.www.DigestAuthenticationFilter"> |
| 20 |
<property name="userDetailsService" ref="inMemoryUserService"/> |
| 21 |
<property name="authenticationEntryPoint" ref="digestEntryPoint"/> |
| 22 |
</bean> |
| 23 |
<bean id="digestEntryPoint" class="pl.arrowgroup.restauth.security.AjaxDigestAuthenticationEntryPoint"> |
| 24 |
<property name="realmName" value="REST-Realm"/> |
| 25 |
<property name="key" value="testNonce"/> |
| 26 |
<property name="nonceValiditySeconds" value="10000"/> |
| 27 |
</bean> |
| 28 |
|
| 29 |
|
| 30 |
<security:authentication-manager alias="authenticationManager"> |
| 31 |
<security:authentication-provider ref="inMemoryAuthenticationProvider"/> |
| 32 |
</security:authentication-manager> |
| 33 |
</beans> |
Authentication provider settings (users/passwords/roles) – security-inmemory-auth-provider.xml
| XML | | copy code | | ? |
| 01 |
<?xml version="1.0" encoding="UTF-8"?> |
| 02 |
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| 03 |
xmlns:security="http://www.springframework.org/schema/security" |
| 04 |
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd |
| 05 |
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> |
| 06 |
|
| 07 |
<bean id="inMemoryAuthenticationProvider" |
| 08 |
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider"> |
| 09 |
<property name="hideUserNotFoundExceptions" value="false"/> |
| 10 |
<property name="userDetailsService" ref="inMemoryUserService"/> |
| 11 |
<property name="messageSource" ref="messageSource"/> |
| 12 |
</bean> |
| 13 |
|
| 14 |
<security:user-service id="inMemoryUserService"> |
| 15 |
<security:user name="marcin" password="michalski" authorities="ROLE_USER"/> |
| 16 |
</security:user-service> |
| 17 |
</beans> |
Servlet front controller configuration (SpringMVC) – servlet-context.xml
| XML | | copy code | | ? |
| 01 |
<?xml version="1.0" encoding="UTF-8"?> |
| 02 |
<beans xmlns="http://www.springframework.org/schema/beans" |
| 03 |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| 04 |
xmlns:context="http://www.springframework.org/schema/context" |
| 05 |
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" |
| 06 |
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd |
| 07 |
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd |
| 08 |
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"> |
| 09 |
|
| 10 |
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> |
| 11 |
<property name="defaultStatusCode" value="200"/> |
| 12 |
<property name="defaultErrorView" value="/error"/> |
| 13 |
<property name="exceptionMappings"> |
| 14 |
<props> |
| 15 |
<prop key="org.springframework.security.access.AccessDeniedException">/denied</prop> |
| 16 |
</props> |
| 17 |
</property> |
| 18 |
</bean> |
| 19 |
|
| 20 |
<context:component-scan base-package="pl.arrowgroup.restauth.controllers"/> |
| 21 |
|
| 22 |
<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver"> |
| 23 |
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> |
| 24 |
<property name="prefix" value="/WEB-INF/jsp/"/> |
| 25 |
<property name="suffix" value=".jsp"/> |
| 26 |
</bean> |
| 27 |
|
| 28 |
<mvc:annotation-driven> |
| 29 |
<mvc:message-converters> |
| 30 |
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/> |
| 31 |
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/> |
| 32 |
<bean class="org.springframework.http.converter.BufferedImageHttpMessageConverter"/> |
| 33 |
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/> |
| 34 |
</mvc:message-converters> |
| 35 |
</mvc:annotation-driven> |
| 36 |
|
| 37 |
|
| 38 |
<mvc:resources mapping="/resources/**" location="/resources/"/> |
| 39 |
<bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/> |
| 40 |
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> |
| 41 |
<property name="supportedMethods" value="GET,POST,PUT,HEAD,DELETE"/> |
| 42 |
<property name="messageConverters"> |
| 43 |
<list> |
| 44 |
<ref bean="jsonMessageConverter"/> |
| 45 |
</list> |
| 46 |
</property> |
| 47 |
</bean> |
| 48 |
</beans> |
For simplicity I have created security layer that uses inmemory authentication provider probably in production environment you would like to have user/password information stored in database or LDAP. So in that case all you have to do is change the authentication provider.
Not to get in to much details I just say that I have configured typical SpringMVC context and provided basic security layer with digest authentication.
As you can see almost everything is provided using default Spring classes with one exception AjaxDigestAuthenticationEntryPoint. Although it is my custom class it actually acts like Spring’s DigestAuthenticationEntryPoint and the only difference it does is that it sends Forbidded (403) http status code instead of Unauthorized(401) once authentication fails. It was done to prevent browser from displaying unwanted pop-ups when 401 status is returned.
AjaxDigestAuthenticationEntryPoint.java:
| Java | | copy code | | ? |
| 01 |
package pl.arrowgroup.restauth.security; |
| 02 |
import java.io.IOException; |
| 03 |
|
| 04 |
import javax.servlet.ServletException; |
| 05 |
import javax.servlet.http.HttpServletRequest; |
| 06 |
import javax.servlet.http.HttpServletResponse; |
| 07 |
import javax.servlet.http.HttpServletResponseWrapper; |
| 08 |
|
| 09 |
import org.springframework.security.core.AuthenticationException; |
| 10 |
import org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint; |
| 11 |
|
| 12 |
public class AjaxDigestAuthenticationEntryPoint extends DigestAuthenticationEntryPoint{
|
| 13 |
|
| 14 |
@Override |
| 15 |
public void commence(HttpServletRequest request, HttpServletResponse response, |
| 16 |
AuthenticationException authException) throws IOException, ServletException {
|
| 17 |
super.commence(request, new UnauthorizedHttpResponse(response), authException); |
| 18 |
} |
| 19 |
|
| 20 |
private static class UnauthorizedHttpResponse extends HttpServletResponseWrapper{
|
| 21 |
public UnauthorizedHttpResponse(HttpServletResponse response) {
|
| 22 |
super(response); |
| 23 |
} |
| 24 |
@Override |
| 25 |
public void sendError(int sc, String msg) throws IOException {
|
| 26 |
if(sc == HttpServletResponse.SC_UNAUTHORIZED){
|
| 27 |
sc = HttpServletResponse.SC_FORBIDDEN; |
| 28 |
} |
| 29 |
super.sendError(sc, msg); |
| 30 |
} |
| 31 |
} |
| 32 |
} |
Web.xml
| XML | | copy code | | ? |
| 01 |
<?xml version="1.0" encoding="UTF-8"?> |
| 02 |
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" |
| 03 |
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" |
| 04 |
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" |
| 05 |
version="2.5"> |
| 06 |
<display-name>${project.name} ${project.version} SVN@${buildNumber}</display-name>
|
| 07 |
<description>${project.description}</description>
|
| 08 |
<context-param> |
| 09 |
<param-name>contextConfigLocation</param-name> |
| 10 |
<param-value>/META-INF/spring/web-application-context.xml</param-value> |
| 11 |
</context-param> |
| 12 |
<context-param> |
| 13 |
<param-name>log4jConfigLocation</param-name> |
| 14 |
<param-value>classpath:log4j.xml</param-value> |
| 15 |
</context-param> |
| 16 |
<!-- ================================================================== --> |
| 17 |
|
| 18 |
<listener> |
| 19 |
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> |
| 20 |
</listener> |
| 21 |
|
| 22 |
<!-- ================================================================== --> |
| 23 |
|
| 24 |
<filter> |
| 25 |
<filter-name>characterEncodingFilter</filter-name> |
| 26 |
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> |
| 27 |
<init-param> |
| 28 |
<param-name>encoding</param-name> |
| 29 |
<param-value>utf-8</param-value> |
| 30 |
</init-param> |
| 31 |
</filter> |
| 32 |
<filter-mapping> |
| 33 |
<filter-name>characterEncodingFilter</filter-name> |
| 34 |
<url-pattern>/*</url-pattern> |
| 35 |
</filter-mapping> |
| 36 |
|
| 37 |
<filter> |
| 38 |
<filter-name>springSecurityFilterChain</filter-name> |
| 39 |
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> |
| 40 |
</filter> |
| 41 |
<filter-mapping> |
| 42 |
<filter-name>springSecurityFilterChain</filter-name> |
| 43 |
<url-pattern>/*</url-pattern> |
| 44 |
</filter-mapping> |
| 45 |
|
| 46 |
<!-- ================================================================== --> |
| 47 |
|
| 48 |
<servlet> |
| 49 |
<servlet-name>springServlet</servlet-name> |
| 50 |
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> |
| 51 |
<init-param> |
| 52 |
<param-name>contextConfigLocation</param-name> |
| 53 |
<param-value>/META-INF/spring/servlet-context.xml</param-value> |
| 54 |
</init-param> |
| 55 |
<load-on-startup>1</load-on-startup> |
| 56 |
</servlet> |
| 57 |
<servlet-mapping> |
| 58 |
<servlet-name>springServlet</servlet-name> |
| 59 |
<url-pattern>/</url-pattern> |
| 60 |
</servlet-mapping> |
| 61 |
</web-app> |
No magic in the web.xml. Just typical Spring + Spring Security configuration.
JavaScript client
As you can see Spring provides almost everything in server side and if we were using Java as a Rest client we could use RestTemplate to have all the work made for us. However we want to use JavaScript instead. In order to do that I had to write mechanism that parses incomming WWW-Authenticate header and generate Authorization header according to RFC 2617.
digest-auth.js:
| Javascript | | copy code | | ? |
| 01 |
/* |
| 02 |
* A JavaScript implementation of the Digest Authentication |
| 03 |
* Digest Authentication, as defined in RFC 2617. |
| 04 |
* Version 1.0 Copyright (C) Maricn Michalski (http://marcin-michalski.pl) |
| 05 |
* Distributed under the BSD License |
| 06 |
* |
| 07 |
* site: http://arrowgroup.eu |
| 08 |
*/ |
| 09 |
|
| 10 |
$.Class("pl.arrowgroup.DigestAuthentication", {
|
| 11 |
MAX_ATTEMPTS : 1, |
| 12 |
AUTHORIZATION_HEADER : "Authorization", |
| 13 |
WWW_AUTHENTICATE_HEADER : 'WWW-Authenticate', |
| 14 |
NC : "00000001", //currently nc value is fixed it is not incremented |
| 15 |
HTTP_METHOD : "GET", |
| 16 |
/** |
| 17 |
* settings json: |
| 18 |
* - onSuccess - on success callback |
| 19 |
* - onFailure - on failure callback |
| 20 |
* - username - user name |
| 21 |
* - password - user password |
| 22 |
* - cnonce - client nonce |
| 23 |
*/ |
| 24 |
init : function(settings) {
|
| 25 |
this.settings = settings; |
| 26 |
}, |
| 27 |
setCredentials: function(username, password){
|
| 28 |
this.settings.username = username; |
| 29 |
this.settings.password = password; |
| 30 |
}, |
| 31 |
call : function(uri){
|
| 32 |
this.attempts = 0; |
| 33 |
this.invokeCall(uri); |
| 34 |
}, |
| 35 |
invokeCall: function(uri,authorizationHeader){
|
| 36 |
var digestAuth = this; |
| 37 |
$.ajax({
|
| 38 |
url: uri, |
| 39 |
type: this.HTTP_METHOD, |
| 40 |
beforeSend: function(request){
|
| 41 |
if(typeof authorizationHeader != 'undefined'){
|
| 42 |
request.setRequestHeader(digestAuth.AUTHORIZATION_HEADER, authorizationHeader); |
| 43 |
} |
| 44 |
}, |
| 45 |
success: function(response) {
|
| 46 |
digestAuth.settings.onSuccess(response); |
| 47 |
}, |
| 48 |
error: function(response) {
|
| 49 |
if(digestAuth.attempts == digestAuth.MAX_ATTEMPTS){
|
| 50 |
digestAuth.settings.onFailure(response); |
| 51 |
return; |
| 52 |
} |
| 53 |
var paramParser = new pl.arrowgroup.HeaderParamsParser(response.getResponseHeader(digestAuth.WWW_AUTHENTICATE_HEADER)); |
| 54 |
var nonce = paramParser.getParam("nonce");
|
| 55 |
var realm = paramParser.getParam("realm");
|
| 56 |
var qop = paramParser.getParam("qop");
|
| 57 |
var response = digestAuth.calculateResponse(uri, nonce, realm, qop); |
| 58 |
var authorizationHeaderValue = digestAuth.generateAuthorizationHeader(paramParser.headerValue, response, uri); |
| 59 |
digestAuth.attempts++; |
| 60 |
digestAuth.invokeCall(uri, authorizationHeaderValue); |
| 61 |
} |
| 62 |
}); |
| 63 |
}, |
| 64 |
calculateResponse : function(uri, nonce, realm, qop){
|
| 65 |
var a2 = this.HTTP_METHOD + ":" + uri; |
| 66 |
var a2Md5 = hex_md5(a2); |
| 67 |
var a1Md5 = hex_md5(this.settings.username + ":" + realm + ":" + this.settings.password); |
| 68 |
var digest = a1Md5 + ":" + nonce + ":" + this.NC + ":" + this.settings.cnonce + ":" + qop + ":" +a2Md5; |
| 69 |
return hex_md5(digest); |
| 70 |
}, |
| 71 |
generateAuthorizationHeader : function(wwwAuthenticationHeader, response, uri){
|
| 72 |
return wwwAuthenticationHeader+', username="'+this.settings.username+'", uri="'+ |
| 73 |
uri+'", response="'+response+'", nc='+ |
| 74 |
this.NC+', cnonce="'+this.settings.cnonce+'"'; |
| 75 |
} |
| 76 |
}); |
| 77 |
$.Class("pl.arrowgroup.HeaderParamsParser",{
|
| 78 |
init : function(headerValue) {
|
| 79 |
this.headerValue = headerValue; |
| 80 |
this.headerParams = this.headerValue.split(",");
|
| 81 |
}, |
| 82 |
getParam: function(paramName){
|
| 83 |
var paramVal = null; |
| 84 |
$.each(this.headerParams, function(index, value){
|
| 85 |
if(value.indexOf(paramName)>0){
|
| 86 |
paramVal = value.split(paramName+"=")[1]; |
| 87 |
paramVal = paramVal.substring(1, paramVal.length-1); |
| 88 |
} |
| 89 |
}); |
| 90 |
return paramVal; |
| 91 |
} |
| 92 |
}); |
In order to prepare JavaScript client I had to use external JS library responsible for MD5 calculation.
| Java | | copy code | | ? |
| 01 |
package pl.arrowgroup.restauth.controllers; |
| 02 |
|
| 03 |
import java.util.Date; |
| 04 |
|
| 05 |
import javax.servlet.http.HttpServletRequest; |
| 06 |
import javax.servlet.http.HttpServletResponse; |
| 07 |
|
| 08 |
import org.springframework.security.core.context.SecurityContextHolder; |
| 09 |
import org.springframework.security.core.userdetails.User; |
| 10 |
import org.springframework.stereotype.Controller; |
| 11 |
import org.springframework.web.bind.annotation.RequestMapping; |
| 12 |
import org.springframework.web.bind.annotation.ResponseBody; |
| 13 |
|
| 14 |
|
| 15 |
@Controller |
| 16 |
@RequestMapping("/user")
|
| 17 |
public class UserController {
|
| 18 |
@RequestMapping(value="/echo") |
| 19 |
public @ResponseBody String echo(HttpServletRequest request, HttpServletResponse resp){
|
| 20 |
return "Hello "+((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername()+ |
| 21 |
" - Current Date is : "+new Date() +" - Visit us at : http://arrowgroup.eu"; |
| 22 |
} |
| 23 |
} |
Client side html – test.html
| HTML | | copy code | | ? |
| 01 | |
| 02 |
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> |
| 03 |
<head > |
| 04 |
<title>Ajax test call</title> |
| 05 |
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> |
| 06 |
<script type="text/javascript" src="../../resources/js/jquery.min.js" ></script> |
| 07 |
<script type="text/javascript" src="../../resources/js/jquery.class.min.js" ></script> |
| 08 |
<script type="text/javascript" src="../../resources/js/md5-min.js" ></script> |
| 09 |
<script type="text/javascript" src="../../resources/js/digest-auth.js" ></script> |
| 10 |
|
| 11 |
<script type="text/javascript"> |
| 12 |
var digestAuth = new pl.arrowgroup.DigestAuthentication( |
| 13 |
{
|
| 14 |
onSuccess : function(response){
|
| 15 |
$("#response").html(response);
|
| 16 |
}, |
| 17 |
onFailure : function(response){
|
| 18 |
$("#response").html('Invalid credentials !!!');
|
| 19 |
}, |
| 20 |
cnonce : 'testCnonce' |
| 21 |
} |
| 22 |
); |
| 23 |
function callREST(){
|
| 24 |
digestAuth.setCredentials($('#user').val(),$('#password').val());
|
| 25 |
digestAuth.call('/restauth/user/echo');
|
| 26 |
} |
| 27 |
</script> |
| 28 |
</head> |
| 29 |
<body> |
| 30 |
<div> |
| 31 |
<h3>Test example of Digest Authentication using Ajax request and Spring Security</h3> |
| 32 |
</div> |
| 33 |
<div> |
| 34 |
<form > |
| 35 |
<p>User <input id="user" type="text" value="marcin"></p> |
| 36 |
<p>Password <input id="password" type="text" value="michalski"></p> |
| 37 |
<p> <button onclick="callREST(); return false;" >Execute</button> |
| 38 |
</form> |
| 39 |
</div> |
| 40 |
<div id="response"> |
| 41 |
</div> |
| 42 |
<div style="color: gray; font-size: 12px;"> |
| 43 |
Copyright 2012: <a href="http://arrowgroup.eu">ArrowGroup</a>, Author: <a href="http://marcin-michalski.pl">Marcin Michalski</a> |
| 44 |
</div> |
| 45 |
</body> |
| 46 |
</html> |
No when we enter the page and provide incorrect password we will be notified that provided password is incorrect:

And when we enter correct password we are able to access the controller method:

security with restful的更多相关文章
- Spring Security开发Restful服务
2-1开发环境安装 1.jdk8安装 2.安装STS Spring Tool Suite实际上就是一个eclipse,只不过在此基础上又安装了一些插件 3.安装mysql 2-2代码结构介绍 打 ...
- 使用Spring Security Oauth2完成RESTful服务password认证的过程
摘要:Spring Security与Oauth2整合步骤中详细描述了使用过程,但它对于入门者有些重量级,比如将用户信息.ClientDetails.token存入数据库而非内存.配置 ...
- 通过Spring Session实现新一代的Session管理
长期以来,session管理就是企业级Java中的一部分,以致于我们潜意识就认为它是已经解决的问题,在最近的记忆中,我们没有看到这个领域有很大的革新. 但是,现代的趋势是微服务以及可水平扩展的原生云应 ...
- 转:通过Spring Session实现新一代的Session管理
长期以来,session管理就是企业级Java中的一部分,以致于我们潜意识就认为它是已经解决的问题,在最近的记忆中,我们没有看到这个领域有很大的革新. 但是,现代的趋势是微服务以及可水平扩展的原生云应 ...
- Spring Security框架下Restful Token的验证方案
项目使用Restful的规范,权限内容的访问,考虑使用Token验证的权限解决方案. 验证方案(简要概括): 首先,用户需要登陆,成功登陆后返回一个Token串: 然后用户访问有权限的内容时需要上传T ...
- Spring Boot+Spring Security+JWT 实现 RESTful Api 权限控制
摘要:用spring-boot开发RESTful API非常的方便,在生产环境中,对发布的API增加授权保护是非常必要的.现在我们来看如何利用JWT技术为API增加授权保护,保证只有获得授权的用户才能 ...
- Spring Boot+Spring Security+JWT 实现 RESTful Api 认证(二)
Spring Boot+Spring Security+JWT 实现 RESTful Api 认证(二) 摘要 上一篇https://javaymw.com/post/59我们已经实现了基本的登录和t ...
- Spring Boot+Spring Security+JWT 实现 RESTful Api 认证(一)
标题 Spring Boot+Spring Security+JWT 实现 RESTful Api 认证(一) 技术 Spring Boot 2.Spring Security 5.JWT 运行环境 ...
- 使用Spring Security和OAuth2实现RESTful服务安全认证
这篇教程是展示如何设置一个OAuth2服务来保护REST资源. 源代码下载github. (https://github.com/iainporter/oauth2-provider)你能下载这个源码 ...
随机推荐
- SICP第三章题解
目录 SICP第三章题解 ex3-17 ex3-18 ex3-19 队列 ex3-21 ex3-22 ex3-24 ex3-25 3.4 并发:时间是一个本质问题 ex3-38 3.4.2 控制并发的 ...
- 使用qt+visa实现程控
曾经在如何使用VS2010调用visa进行程控中使用vs2010+visa 实现了程控最简单的Demo,现实现Qt实现visa的Demo ===== 本人诚接各种程控开发项目 ===== 软件环境 系 ...
- Python之路【第三篇】:文件操作
一.文件操作步骤 打开文件,得到文件句柄并赋值给一个变量 通过句柄对文件进行操作 关闭文件 歌名:<大火> 演唱:李佳薇 作词:姚若龙 作曲:马奕强 歌词: 有座巨大的停了的时钟 倾倒在赶 ...
- 如何正确地使用Java的@deprecated标注
没有什么事情比看到一个没有任何说明的@deprecated标注更让人愤怒的事情了.这种做法只能让人困惑,我到底还要不要用这个已经‘废弃’的方法?如果开发者不希望某个方法再被人用的话,就要好好地为@de ...
- Host aggregate分区
问题描述:生产区一期环境增加4台计算结点,希望被大数据租户独占1. 该大数据用户创建的虚拟机必须被调度到这4个计算结点2. 其他租户创建虚拟机禁止调度到这4台机器 标黄的需要自行根据情况修改解决方案: ...
- 常见http错误码
一些常见的状态码为: 200 - 服务器成功返回网页 404 - 请求的网页不存在 503 - 服务不可用 详细分解: 1xx(临时响应) 表示临时响应并需要请求者继续执行操作的状态代码. 代码 说明 ...
- 交叉编译iperf源代码
<Iperf简介> Iperf 是一个网络性能测试工具.Iperf可以测试最大TCP和UDP带宽性能,具有多种参数和UDP特性,可以根据需要调整,可以报告带宽.延迟抖动和数据包丢失. &l ...
- functools.wraps 带参数的装饰器 多个装饰器装饰同一个函数
装饰器开发原则 : 开放封闭原则装饰器的作用 :在不改变原函数的调用方式的情况下,在函数的前后添加功能装饰器的本质 : 闭包函数 def wrapper(func): def inner(*args, ...
- codevs 5294 挖地雷
5294 挖地雷 时间限制: 1 s 空间限制: 1000 KB 题目等级 : 黄金 Gold 题目描述 Description 在一个地图上有N个地窖(N<=20),每个地窖中埋有一 ...
- [CodeForces-332E]Binary Key
题目大意: 给你两个字符串p和s,让你求出一个字典序尽量小的长度为k的01串密钥,能将p转化为s. 密钥的工作方式如下: 第i位是0,表示这一位无用: 第i位是1,表示这一位有用. 若密钥的长度比s短 ...