oauth2 java 服务端_oauth2 学习(一)-使用Apache oltu实现oauth2的授权服务器

本文介绍了使用Apache Oltu库在Java环境中搭建OAuth2授权服务器的过程。通过登录接口、授权码接口、访问令牌接口的详细实现,阐述了OAuth2的主要流程,包括客户端验证、授权码生成和访问令牌的管理。
摘要由CSDN通过智能技术生成

最近做oauth2预研,查了相当多的资料

因为现有的项目是使用java 语言来实现的,且不打算直接去实现这一整套的标准。因此先去官网(https://oauth.net/code/)看了下现有的java版实现。其实还有其他的实现没有收录进去。

be0cd0b5077b5430a23c44a4babb09ee.png

比较之后发现资料相对较多的是Apache oltu以及 spring sercurity oauth.因为都是开源的,就去把源代码都clone下来了。个人认为Oltu相对来说更轻量,也更简单,是对oauth2的简单实现。很多后续校验的事情都需要我们自己去做,但这也是它灵活的一面。所以一开始,是决定使用Apache 的oltu。参考了杨开涛的博客(OAuth2集成——《跟我学Shiro》)使用oltu实现了一个简单的认证服务器。

一开始是打算写三个服务的oauthservice,oauthclient,oauthresource,后来为了省时间直接把客户端也集成到服务里面了,交互界面也只是几个简单的输入框。

认证服务主要有几个接口

/login:登录接口

/Oauth/authorize:获取授权码的接口

/Oauth/getCode:这个其实就是授权码接口,只是例子中后端没有存储登录状态,做了个中转

/Oauth/ accesstoken:获取访问令牌

下面来说说每个接口具体做了什么事

获取授权码将请求转换成oltu的认证请求OauthAuthzRequest

从 OauthAuthzRequest 读取客户端信息(clientId,redirectUrl,response_type)

校验客户端信息

校验成功后生成访问令牌

存储访问令牌

使用oltu的OAuthASResponse构建oauth响应

在响应中设置好授权码,state等信息

重定向到客户端的redirectUrl

public Object getCode(HttpServletRequest request) {

try {

OAuthAuthzRequest oauthRequest = new OAuthAuthzRequest(request);

OAuthResponse oAuthResponse;

String clientId=oauthRequest.getClientId();

//校验client信息

if(!oauthClientService.checkClient(clientId))

{

return ControllerHelper

.getResponseEntity(HttpServletResponse.SC_BAD_REQUEST

, OAuthError.TokenResponse.INVALID_CLIENT

, ErrorConstants.ERROR_CLIENT_MSG);

}

//获取登陆信息

//已经登录校验内部token信息,没有登陆,校验登陆信息

String token=request.getParameter("token");

if(StringUtils.isEmpty(token))//token不存在及用户没有登陆,非法访问

{

return ControllerHelper

.getResponseEntity(HttpServletResponse.SC_BAD_REQUEST

, OAuthError.CodeResponse.ACCESS_DENIED

, ErrorConstants.ERROR_CLIENT_LOGIN);

}

else {//校验token 服务器端对应的token是否存在,及获取用户信息等

//checktoken()

}

//生成授权码

String authcode=null;

String responseType=oauthRequest.getParam(OAuth.OAUTH_RESPONSE_TYPE);

if(responseType.equals(ResponseType.CODE.toString()))

{

OAuthIssuerImpl oAuthIssuerImpl=new OAuthIssuerImpl(new MD5Generator());

authcode=oAuthIssuerImpl.authorizationCode();

//保存授权码

oauthClientService.saveCode(clientId, authcode);

}

//Oauth 响应

OAuthASResponse.OAuthAuthorizationResponseBuilder builder=

OAuthASResponse.authorizationResponse(request, HttpServletResponse.SC_FOUND);

//设置授权码

builder.setCode(authcode);

String redirectURI=oauthRequest.getParam(OAuth.OAUTH_REDIRECT_URI);

oAuthResponse=builder.location(redirectURI).buildQueryMessage();

//根据OAuthResponse返回ResponseEntity响应

HttpHeaders headers = new HttpHeaders();

headers.setLocation(new URI(oAuthResponse.getLocationUri()));

return new ResponseEntity(headers, HttpStatus.valueOf(oAuthResponse.getResponseStatus()));

} catch (Exception e) {

logger.error(e.getCause().getMessage(),e);

}

return null;

}

获取访问令牌将请求转换成oltu的token 获取请求OAuthTokenRequest

从OauthTokenRequest读取客户端信息

校验客户端信息

生成访问令牌token

存储访问令牌

构建oauth2响应oAuthResponse

返回到客户端

public Object getToken(HttpServletRequest request) throws OAuthSystemException {

try {

OAuthTokenRequest oAuthTokenRequest= new OAuthTokenRequest(request);

String clientId=oAuthTokenRequest.getClientId();

String clientKey= oAuthTokenRequest.getClientSecret();

if(!oauthClientService.checkClient(clientId,clientKey))

{

return ControllerHelper.getResponseEntity(HttpServletResponse.SC_BAD_REQUEST, OAuthError.TokenResponse.INVALID_CLIENT, ErrorConstants.ERROR_CLIENT_MSG);

}

OAuthResponse oAuthResponse;

String authcode= oAuthTokenRequest.getCode();

String grantType= oAuthTokenRequest.getGrantType();

if(GrantType.AUTHORIZATION_CODE.toString().equals(grantType) && authcode.equals(oauthClientService.getCode(clientId)))

{

//生成token

OAuthIssuer oauthIssuerImpl = new OAuthIssuerImpl(new MD5Generator());

final String accessToken = oauthIssuerImpl.accessToken();

oauthClientService.saveAccessToken(accessToken, "");

//生成OAuth响应

oAuthResponse = OAuthASResponse

.tokenResponse(HttpServletResponse.SC_OK)

.setAccessToken(accessToken)

.setExpiresIn(String.valueOf( 3600L))

.buildJSONMessage();

//根据OAuthResponse生成ResponseEntity

return new ResponseEntity(oAuthResponse.getBody(), HttpStatus.valueOf(oAuthResponse.getResponseStatus()));

}

else{

return ControllerHelper.getResponseEntity(HttpServletResponse.SC_BAD_REQUEST, OAuthError.TokenResponse.INVALID_GRANT, ErrorConstants.ERROR_AUTH_CODE);

}

} catch (Exception e) {

logger.error(e.getMessage(),e);

return ControllerHelper.getResponseEntity(HttpServletResponse.SC_BAD_REQUEST, ErrorConstants.ERROR_UNKNOW, e.getCause().getMessage());

}

}

客户端主要有一下两个接口

/requestAuth: 重定向到拼接好的授权请求url

@RequestMapping("/requestAuth")

public ModelAndView requestAuth(@ModelAttribute("oauthParams") OauthParam oauthParams) {

try {

OAuthClientRequest request = OAuthClientRequest

.authorizationLocation(oauthParams.getAuthzEndpoint())

.setClientId(oauthParams.getClientId())

.setRedirectURI(oauthParams.getRedirectUri())

.setResponseType(ResponseType.CODE.toString())

.setScope(oauthParams.getScope())

.setState(oauthParams.getState())

.buildQueryMessage();

return new ModelAndView(new RedirectView(request.getLocationUri()));

} catch (Exception e) {

logger.error(e.getMessage(),e);

return null;

}

}

/redirect:获取授权码后,处理授权码的重定向地址。

OAuthAuthzResponse oar = null;

oar = OAuthAuthzResponse.oauthCodeAuthzResponse(request);

String code = oar.getCode();//获取授权码

OAuthClientRequest request2 =OAuthClientRequest

.tokenLocation(oauthParams.getTokenEndpoint())

.setClientId(oauthParams.getClientId())

.setClientSecret(oauthParams.getClientSecret())

.setRedirectURI(oauthParams.getRedirectUri())

.setCode(code)

.setGrantType(GrantType.AUTHORIZATION_CODE)

.buildBodyMessage();

OAuthClient client=new OAuthClient(new URLConnectionClient());

Class extends OAuthAccessTokenResponse> cl = OAuthJSONAccessTokenResponse.class;

//请求token

OAuthAccessTokenResponse oauthResponse=client.accessToken(request2,cl);

String token=oauthResponse.getAccessToken();//获取token

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值