spring security oauth2 自定义实现令牌存储

时间:2022-12-19 21:05:32

我一开始用oauth2 for spring security的JdbcTokenStore存储令牌,它用jdbcTemplate操作数据库,代码显示操作成功,但是数据库里就是没有存储的令牌,调试搞了一天,就是找不到原因,无奈,只好自己用mybatis实现了一个tokenStore。

数据库表结构:

drop table if exists oauth_client_details;
drop table if exists oauth_access_token;
drop table if exists oauth_refresh_token;
drop table if exists oauth_code;

create table oauth_client_details (
  client_id VARCHAR(50) PRIMARY KEY,
  resource_ids VARCHAR(256),
  client_secret VARCHAR(256),
  scope VARCHAR(256),
  authorized_grant_types VARCHAR(256),
  web_server_redirect_uri VARCHAR(256),
  authorities VARCHAR(256)
);

create table oauth_access_token (
  token_id VARCHAR(256),
  token blob,
  authentication_id VARCHAR(256),
  authentication blob,
  refresh_token VARCHAR(256)
);

create table oauth_refresh_token (
  token_id VARCHAR(256),
  token blob,
  authentication blob
);

create table oauth_code (
  code VARCHAR(256),
  authentication blob
);

insert into oauth_client_details(client_id,resource_ids,client_secret,scope,authorized_grant_types,authorities) 
values('client','sparklr','secret','read,write','authorization_code','ROLE_CLIENT');



几个实体类如下:

package com.hxp.oauth.server.entity;

import java.io.Serializable;

public class MybatisOauth2AccessToken implements Serializable {
	private static final long serialVersionUID = -4232065232755289541L;

	private String tokenId;
	private byte[] token;
	private String authenticationId;
	private byte[] authentication;
	private String refreshToken;

	public String getTokenId() {
		return tokenId;
	}

	public void setTokenId(String tokenId) {
		this.tokenId = tokenId;
	}

	public byte[] getToken() {
		return token;
	}

	public void setToken(byte[] token) {
		this.token = token;
	}

	public String getAuthenticationId() {
		return authenticationId;
	}

	public void setAuthenticationId(String authenticationId) {
		this.authenticationId = authenticationId;
	}

	public byte[] getAuthentication() {
		return authentication;
	}

	public void setAuthentication(byte[] authentication) {
		this.authentication = authentication;
	}

	public String getRefreshToken() {
		return refreshToken;
	}

	public void setRefreshToken(String refreshToken) {
		this.refreshToken = refreshToken;
	}

	

}

package com.hxp.oauth.server.entity;

import java.io.Serializable;

public class MybatisOauth2RefreshToken implements Serializable {
	private static final long serialVersionUID = 238497479380096784L;

	private String tokenId;
	private byte[] token;
	private byte[] authentication;

	public String getTokenId() {
		return tokenId;
	}

	public void setTokenId(String tokenId) {
		this.tokenId = tokenId;
	}

	public byte[] getToken() {
		return token;
	}

	public void setToken(byte[] token) {
		this.token = token;
	}

	public byte[] getAuthentication() {
		return authentication;
	}

	public void setAuthentication(byte[] authentication) {
		this.authentication = authentication;
	}

}

package com.hxp.oauth.server.entity;

import java.io.Serializable;

public class MybatisOauth2Code implements Serializable {
	private static final long serialVersionUID = -1799776184263988216L;

	private String code;
	private byte[] authentication;

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public byte[] getAuthentication() {
		return authentication;
	}

	public void setAuthentication(byte[] authentication) {
		this.authentication = authentication;
	}

}


tokenStore类:

package com.hxp.oauth.server.store;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.util.SerializationUtils;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.AuthenticationKeyGenerator;
import org.springframework.security.oauth2.provider.token.DefaultAuthenticationKeyGenerator;
import org.springframework.security.oauth2.provider.token.TokenStore;

import com.hxp.oauth.server.dao.MybatisTokenDao;
import com.hxp.oauth.server.entity.MybatisOauth2AccessToken;
import com.hxp.oauth.server.entity.MybatisOauth2RefreshToken;

public class MybatisTokenStore implements TokenStore {
	private static final Log LOG = LogFactory.getLog(MybatisTokenStore.class);
	
	private MybatisTokenDao mybatisTokenDao;
	
	private AuthenticationKeyGenerator authenticationKeyGenerator = new DefaultAuthenticationKeyGenerator();
	
	
	public OAuth2Authentication readAuthentication(OAuth2AccessToken token) {
		OAuth2Authentication authentication = null;

		try {
			MybatisOauth2AccessToken at=mybatisTokenDao.readAccessToken( token.getValue());
			authentication = SerializationUtils.deserialize(at.getAuthentication());
					
		}
		catch (EmptyResultDataAccessException e) {
			if (LOG.isInfoEnabled()) {
				LOG.info("Failed to find access token for token " + token);
			}
		}

		return authentication;
	}

	public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
		String refreshToken = null;
		if (token.getRefreshToken() != null) {
			refreshToken = token.getRefreshToken().getValue();
		}
		MybatisOauth2AccessToken at=new MybatisOauth2AccessToken();
		at.setTokenId(token.getValue());
		at.setToken(SerializationUtils.serialize(token));
		at.setAuthenticationId(authenticationKeyGenerator.extractKey(authentication));
		at.setAuthentication(SerializationUtils.serialize(authentication));
		at.setRefreshToken(refreshToken);
		mybatisTokenDao.storeAccessToken(at);
	}

	public OAuth2AccessToken readAccessToken(String tokenValue) {
		OAuth2AccessToken accessToken = null;

		try {
			accessToken = SerializationUtils.deserialize(mybatisTokenDao.readAccessToken(tokenValue).getToken());			
		}
		catch (EmptyResultDataAccessException e) {
			if (LOG.isInfoEnabled()) {
				LOG.info("Failed to find access token for token " + tokenValue);
			}
		}

		return accessToken;
	}

	public void removeAccessToken(String tokenValue) {
		mybatisTokenDao.removeAccessToken(tokenValue);

	}

	public OAuth2Authentication readAuthentication(ExpiringOAuth2RefreshToken token) {
		OAuth2Authentication authentication = null;

		try {
			authentication = SerializationUtils.deserialize(mybatisTokenDao.readRefreshToken(token.getValue()).getAuthentication());
		}
		catch (EmptyResultDataAccessException e) {
			if (LOG.isInfoEnabled()) {
				LOG.info("Failed to find access token for token " + token);
			}
		}

		return authentication;
	}

	public void storeRefreshToken(ExpiringOAuth2RefreshToken refreshToken, OAuth2Authentication authentication) {
		MybatisOauth2RefreshToken rt=new MybatisOauth2RefreshToken();
		rt.setTokenId(refreshToken.getValue());
		rt.setToken(SerializationUtils.serialize(refreshToken));
		rt.setAuthentication(SerializationUtils.serialize(authentication));
		mybatisTokenDao.storeRefreshToken(rt);
	}

	public ExpiringOAuth2RefreshToken readRefreshToken(String tokenValue) {
		ExpiringOAuth2RefreshToken refreshToken = null;

		try {
			refreshToken = SerializationUtils.deserialize(mybatisTokenDao.readRefreshToken(tokenValue).getToken());
		}
		catch (EmptyResultDataAccessException e) {
			if (LOG.isInfoEnabled()) {
				LOG.info("Failed to find refresh token for token " + tokenValue);
			}
		}

		return refreshToken;
	}

	public void removeRefreshToken(String tokenValue) {
		mybatisTokenDao.removeRefreshToken(tokenValue);

	}

	public void removeAccessTokenUsingRefreshToken(String refreshToken) {
		mybatisTokenDao.removeAccessTokenUsingRefreshToken(refreshToken);

	}

	public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
		OAuth2AccessToken accessToken = null;

		try {
			String auth=authenticationKeyGenerator.extractKey(authentication);
			 MybatisOauth2AccessToken at=mybatisTokenDao.getAccessToken(auth);
			if(null==at){
				return null;
			}else{
				accessToken = SerializationUtils.deserialize(at.getToken());
			}
				
		}
		catch (EmptyResultDataAccessException e) {
			if (LOG.isInfoEnabled()) {
				LOG.debug("Failed to find access token for authentication " + authentication);
			}
		}

		return accessToken;
	}

	public MybatisTokenDao getMybatisTokenDao() {
		return mybatisTokenDao;
	}

	public void setMybatisTokenDao(MybatisTokenDao mybatisTokenDao) {
		this.mybatisTokenDao = mybatisTokenDao;
	}
	
	

}

dao接口类:

package com.hxp.oauth.server.dao;

import com.hxp.oauth.server.entity.MybatisOauth2AccessToken;
import com.hxp.oauth.server.entity.MybatisOauth2RefreshToken;

public interface MybatisTokenDao {	
    void storeAccessToken(MybatisOauth2AccessToken token);
    
    MybatisOauth2AccessToken readAccessToken(String tokenValue);

	 void removeAccessToken(String tokenValue);

	 void storeRefreshToken(MybatisOauth2RefreshToken token);

	 MybatisOauth2RefreshToken readRefreshToken(String tokenValue);

	 void removeRefreshToken(String tokenValue);

	 void removeAccessTokenUsingRefreshToken(String refreshToken);

	 MybatisOauth2AccessToken getAccessToken(String authentication);
}

mapper 配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.hxp.oauth.server.dao.MybatisTokenDao">
	<resultMap id="accessToken" type="com.hxp.oauth.server.entity.MybatisOauth2AccessToken">
		<result property="tokenId" column="token_id" />
		<result property="token" column="token" />
		<result property="authenticationId" column="authentication_id" />
		<result property="authentication" column="authentication" />
		<result property="refreshToken" column="refresh_token" />
	</resultMap>
	<resultMap id="refreshToken" type="com.hxp.oauth.server.entity.MybatisOauth2RefreshToken">
		<result property="tokenId" column="token_id" />
		<result property="token" column="token" />
		<result property="authentication" column="authentication" />
	</resultMap>
	<resultMap id="code" type="com.hxp.oauth.server.entity.MybatisOauth2Code">
		<result property="code" column="code" />
		<result property="authentication" column="authentication" />
	</resultMap>
	
	
	<insert id="storeAccessToken" parameterType="com.hxp.oauth.server.entity.MybatisOauth2AccessToken">
		insert into oauth_access_token (token_id, token, authentication_id, authentication, refresh_token) values (#{tokenId}, #{token ,javaType=byte[], jdbcType=BLOB,typeHandler=org.apache.ibatis.type.BlobTypeHandler}, #{authenticationId}, #{authentication ,javaType=byte[], jdbcType=BLOB,typeHandler=org.apache.ibatis.type.BlobTypeHandler}, #{refreshToken})
	</insert>
	
	<select id="readAccessToken" parameterType="string"  resultMap="accessToken">
			select token_id, token,authentication from oauth_access_token where token_id = #{tokenValue}
	</select>
	
	<delete id="removeAccessToken" parameterType="string" >
		delete from oauth_access_token where token_id = #{tokenValue}
	</delete>

	<insert id="storeRefreshToken" parameterType="com.hxp.oauth.server.entity.MybatisOauth2RefreshToken" >
		insert into oauth_refresh_token (token_id, token, authentication) values (#{tokenId}, #{token ,javaType=byte[], jdbcType=BLOB,typeHandler=org.apache.ibatis.type.BlobTypeHandler}, #{authentication ,javaType=byte[], jdbcType=BLOB,typeHandler=org.apache.ibatis.type.BlobTypeHandler})
	</insert>
	
	<select id="readRefreshToken" parameterType="string" resultMap="refreshToken" >
		select token_id, token,authentication from oauth_refresh_token where token_id = #{tokenValue}
	</select>
	
	<delete id="removeRefreshToken" parameterType="string" >
		delete from oauth_refresh_token where token_id = #{tokenValue}
	</delete>
	
	<delete id="removeAccessTokenUsingRefreshToken" parameterType="string" >
		delete from oauth_access_token where refresh_token = #{tokenValue}
	</delete>
	
	<select id="getAccessToken" parameterType="string" resultMap="accessToken">
		select token_id, token from oauth_access_token where authentication_id = #{authentication}
	</select>
</mapper>