认证功能实现(spring-oauth2)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了认证功能实现(spring-oauth2)相关的知识,希望对你有一定的参考价值。
参考技术A 前面讲述了一下 spring security对认证的实现 ,该实现的使用场景主要是用户本人认证。
有一种场景是用户将授权给第三方应用,访问本人在该应用的资源。
站在应用的角度出发,就是经得用户授权以后,对第三方应用认证,获取访问用户资源的权限。
oauth2就是一种用户对第三方应用授权,获取用户在本应用资源访问权限的协议标准。
该协议中针对第三方应用有四种认证方式。
相关认证的类型选择流程如下所示:
关于Spring对oauth2的实现框架图如下所示:
其中:
所以认证的主要逻辑都在认证授权服务上(AuthorizationServer)。
其中:
其中对不同的oauth2协议的认证协议实现,主要是通过 TokenGranter 接口的 grant 方法的实现。
TokenGranter接口及相关的实现类的关系图所下所示:
spring-oauth2 登录成功处理程序
【中文标题】spring-oauth2 登录成功处理程序【英文标题】:spring-oauth2 login success handler 【发布时间】:2015-06-03 01:04:06 【问题描述】:有没有办法使用 spring-oauth2 添加登录成功处理程序?
我尝试使用基本身份验证过滤器,但它只过滤客户端凭据而不是用户凭据。
或者我需要创建一个自定义用户身份验证管理器吗?
TIA
【问题讨论】:
【参考方案1】:我们构建了一个自定义身份验证管理器,我们将其连接到 OAuth2AuthenticationProcessingFilter 以完成此操作。管理器的身份验证方法能够从身份验证主体中解压缩 OAuth2Authentication 和 OAuth2AuthenticationDetails。
<bean id="oAuth2AuthenticationManager" class="org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationManager">
<property name="resourceId" value="XXX-api"/>
<property name="tokenServices" ref="tokenServices"/>
</bean>
<bean id="resourceServerFilter"
class="org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter">
<property name="authenticationManager" ref="oAuth2AuthenticationManager"/>
<property name="tokenExtractor">
<bean class="com.xxx.oauth.BearerTokenExtractor"/>
</property>
</bean>
【讨论】:
【参考方案2】:此解决方案适用于密码流以及我不确定的其他解决方案。 您可以在 oauth-server 配置中的 http 标记中的“before=BASIC_AUTH_FILTER”位置添加自定义过滤器, 您可以通过解析“oauth/token”的响应来实现,因此创建 ByteArrayResponseWrapper 来获取响应, 这里我使用来自“org.apache.commons commons-io”的 TeeOutputStream 类,
private class ByteArrayResponseWrapper extends HttpServletResponseWrapper
public ByteArrayResponseWrapper(ServletResponse response)
super((HttpServletResponse) response);
private ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
@Override
public ServletOutputStream getOutputStream() throws IOException
return new DelegatingServletOutputStream(new TeeOutputStream(
super.getOutputStream(), byteArrayOutputStream));
public byte[] getByteArray()
return this.byteArrayOutputStream.toByteArray();
我已经创建了令牌提取器来分离提取access_token的代码
public class OAuth2AccessTokenExtractor implements
OAuth2AccessTokenExtractor
private ObjectMapper mapper = new ObjectMapper();
public String getAccessTokenValue(byte[] response)
try
return mapper.readValue(response, OAuth2AccessToken.class)
.getValue();
catch (JsonParseException e)
e.printStackTrace();
catch (JsonMappingException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
return null;
像这样创建过滤器覆盖 doFilter 后
private DefaultTokenServices tokenServices;
private OAuth2AccessTokenExtractor tokenExtractor;
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException
// create wrapper to read response body
ByteArrayResponseWrapper responseWraper = new ByteArrayResponseWrapper(
response);
// led them go
chain.doFilter(request, responseWraper);
// get ClientAuthentication
Authentication clientAuthentication = SecurityContextHolder
.getContext().getAuthentication();
// is authenticated or not to proceed
if (clientAuthentication != null
&& clientAuthentication.isAuthenticated())
// callBack client authenticated successfully
onSuccessfulClientAuthentication(request, response,
clientAuthentication);
// check response status is success of failure
if (responseWraper.getStatus() == 200)
// extract accessToken from response
String token = tokenExtractor
.getAccessTokenValue(responseWraper.getByteArray());
if (token != null && !token.isEmpty())
// load authentication from token
OAuth2Authentication oAuth2Authentication = this.tokenServices
.loadAuthentication(token);
OAuth2AccessToken actualAccessToken = this.tokenServices
.getAccessToken(oAuth2Authentication);
// callBack user authenticated successfully
onSuccessfulUserAuthentication(request, response,
clientAuthentication, oAuth2Authentication,
actualAccessToken);
else
log.error("access token is empty from extractor");
else
// callBack user authenticated failure
onFailureUserAuthentication(request, response,
clientAuthentication, request.getParameter("username"));
else
// callBack client authenticated failure
onFailClientAuthentication(request, response,
request.getParameter(OAuth2Utils.CLIENT_ID));
protected void onSuccessfulClientAuthentication(ServletRequest request,
ServletResponse response, Authentication authentication)
protected void onFailClientAuthentication(ServletRequest request,
ServletResponse response, String clientId)
protected void onSuccessfulUserAuthentication(ServletRequest request,
ServletResponse response, Authentication clientAuthentication,
OAuth2Authentication userOAuth2Authentication,
OAuth2AccessToken token)
protected void onFailureUserAuthentication(ServletRequest request,
ServletResponse response, Authentication clientAuthentication,
String username)
在创建过滤器实例时注入 tokenServices。 现在 onSuccessfulClientAuthentication、onFailClientAuthentication、onSuccessfulUserAuthentication 和 onFailureUserAuthentication 将根据您的身份验证调用
更多信息您可以在github上参考此代码
已编辑:
当您有默认令牌响应并且它只是使用 ServletResponseWrapper 和提取时,上面的 sn-p 工作正常。
但它似乎仍然容易受到攻击,因此您可以通过org.springframework.security.oauth2.provider.token.TokenEnhancer
类了解用户身份验证成功
关注answer了解详情。
【讨论】:
谢谢。我无法理解为什么 spring oauth2 的作者使用过去运行良好的简单成功/失败处理程序打破了经过验证的设计。 完全同意。对于这样一个基本功能,似乎非常复杂和“hack”-y。 hacky 我的意思是知道实现细节,而不是只使用接口以上是关于认证功能实现(spring-oauth2)的主要内容,如果未能解决你的问题,请参考以下文章
Shiro01 功能点框图架构图身份认证逻辑身份认证代码实现
Spring-OAUTH2.0:调用 /oauth/token 时没有可用资源错误
编译树莓派2代B型OpenWrt固件实现无线路由器及nodogsplash认证功能