假设我们的accessToken是这样的
{ "access_token": "ffb71ed0-5e48-44bc-b4aa-16ee0ba24b01", "token_type": "bearer", "refresh_token": "70220a36-3419-4c48-a60e-2d80b0f1774f", "expires_in": 28799, "scope": "app" }
获取当前用户的Authentication,Authentication是一个接口,具体实现类是OAuth2Authentication,由以下返回结果可知,他是一个包含了大量信息的类.而每一个信息块里面又有着接口和实现类.
@GetMapping("/user-me")
public Authentication principal() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
log.debug("user-me:{}", authentication.getName());
return authentication;
}
请求http://127.0.0.1:50075/user-me?access_token=ffb71ed0-5e48-44bc-b4aa-16ee0ba24b01
返回结果如下
{ "authorities": [ { "authority": "back:menu:set2role" }, { "authority": "mail:update" }, { "authority": "back:permission:delete" }, { "authority": "role:permission:byroleid" }, { "authority": "back:menu:save" }, { "authority": "back:menu:query" }, { "authority": "ip:black:query" }, { "authority": "ip:black:save" }, { "authority": "file:del" }, { "authority": "ip:black:delete" }, { "authority": "mail:query" }, { "authority": "back:user:query" }, { "authority": "back:role:permission:set" }, { "authority": "sms:query" }, { "authority": "back:role:query" }, { "authority": "back:permission:query" }, { "authority": "back:role:save" }, { "authority": "back:user:role:set" }, { "authority": "log:query" }, { "authority": "file:query" }, { "authority": "back:menu:update" }, { "authority": "back:role:update" }, { "authority": "back:role:delete" }, { "authority": "back:user:password" }, { "authority": "ROLE_SUPER_ADMIN" }, { "authority": "back:menu:delete" }, { "authority": "back:user:update" }, { "authority": "menu:byroleid" }, { "authority": "mail:save" }, { "authority": "user:role:byuid" }, { "authority": "back:permission:save" }, { "authority": "back:permission:update" } ], "details": { "remoteAddress": "127.0.0.1", "sessionId": null, "tokenValue": "ffb71ed0-5e48-44bc-b4aa-16ee0ba24b01", "tokenType": "Bearer", "decodedDetails": null }, "authenticated": true, "userAuthentication": { "authorities": [ { "authority": "back:menu:set2role" }, { "authority": "mail:update" }, { "authority": "back:permission:delete" }, { "authority": "role:permission:byroleid" }, { "authority": "back:menu:save" }, { "authority": "back:menu:query" }, { "authority": "ip:black:query" }, { "authority": "ip:black:save" }, { "authority": "file:del" }, { "authority": "ip:black:delete" }, { "authority": "mail:query" }, { "authority": "back:user:query" }, { "authority": "back:role:permission:set" }, { "authority": "sms:query" }, { "authority": "back:role:query" }, { "authority": "back:permission:query" }, { "authority": "back:role:save" }, { "authority": "back:user:role:set" }, { "authority": "log:query" }, { "authority": "file:query" }, { "authority": "back:menu:update" }, { "authority": "back:role:update" }, { "authority": "back:role:delete" }, { "authority": "back:user:password" }, { "authority": "ROLE_SUPER_ADMIN" }, { "authority": "back:menu:delete" }, { "authority": "back:user:update" }, { "authority": "menu:byroleid" }, { "authority": "mail:save" }, { "authority": "user:role:byuid" }, { "authority": "back:permission:save" }, { "authority": "back:permission:update" } ], "details": { "grant_type": "password", "scope": "app", "client_secret": "system", "client_id": "system", "username": "admin|USERNAME" }, "authenticated": true, "principal": { "id": 1, "username": "admin", "password": "$2a$10$3uOoX1ps14CxuotogUoDreW8zXJOZB9XeGdrC/xDV36hhaE8Rn9HO", "nickname": "测试1", "headImgUrl": "", "phone": "", "sex": 1, "enabled": true, "type": "APP", "createTime": "2018-01-17T16:56:59.000+0000", "updateTime": "2018-01-17T16:57:01.000+0000", "sysRoles": [ { "id": 1, "code": "SUPER_ADMIN", "name": "超级管理员", "createTime": "2018-01-19T20:32:16.000+0000", "updateTime": "2018-01-19T20:32:18.000+0000" } ], "permissions": [ "back:menu:set2role", "mail:update", "back:permission:delete", "role:permission:byroleid", "back:menu:save", "back:menu:query", "ip:black:query", "ip:black:save", "file:del", "ip:black:delete", "mail:query", "back:user:query", "back:role:permission:set", "sms:query", "back:role:query", "back:permission:query", "back:role:save", "back:user:role:set", "log:query", "file:query", "back:menu:update", "back:role:update", "back:role:delete", "back:user:password", "back:menu:delete", "back:user:update", "menu:byroleid", "mail:save", "user:role:byuid", "back:permission:save", "back:permission:update" ], "credentialsNonExpired": true, "accountNonExpired": true, "accountNonLocked": true }, "credentials": null, "name": "admin" }, "credentials": "", "principal": { "id": 1, "username": "admin", "password": "$2a$10$3uOoX1ps14CxuotogUoDreW8zXJOZB9XeGdrC/xDV36hhaE8Rn9HO", "nickname": "测试1", "headImgUrl": "", "phone": "", "sex": 1, "enabled": true, "type": "APP", "createTime": "2018-01-17T16:56:59.000+0000", "updateTime": "2018-01-17T16:57:01.000+0000", "sysRoles": [ { "id": 1, "code": "SUPER_ADMIN", "name": "超级管理员", "createTime": "2018-01-19T20:32:16.000+0000", "updateTime": "2018-01-19T20:32:18.000+0000" } ], "permissions": [ "back:menu:set2role", "mail:update", "back:permission:delete", "role:permission:byroleid", "back:menu:save", "back:menu:query", "ip:black:query", "ip:black:save", "file:del", "ip:black:delete", "mail:query", "back:user:query", "back:role:permission:set", "sms:query", "back:role:query", "back:permission:query", "back:role:save", "back:user:role:set", "log:query", "file:query", "back:menu:update", "back:role:update", "back:role:delete", "back:user:password", "back:menu:delete", "back:user:update", "menu:byroleid", "mail:save", "user:role:byuid", "back:permission:save", "back:permission:update" ], "credentialsNonExpired": true, "accountNonExpired": true, "accountNonLocked": true }, "clientOnly": false, "oauth2Request": { "clientId": "system", "scope": [ "app" ], "requestParameters": { "grant_type": "password", "scope": "app", "client_id": "system", "username": "admin|USERNAME" }, "resourceIds": [], "authorities": [], "approved": true, "refresh": false, "redirectUri": null, "responseTypes": [], "extensions": {}, "grantType": "password", "refreshTokenRequest": null }, "name": "admin" }
首先我们需要写一个资源配置类
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter
其中这个@EnableResourceServer实际上帮我们加入了一个过滤器(应该说所有的业务模块都要有一个资源配置类来开启这个过滤器)org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter
在他的源码中有一个doFilter
public class OAuth2AuthenticationProcessingFilter implements Filter, InitializingBean
private TokenExtractor tokenExtractor = new BearerTokenExtractor();
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
boolean debug = logger.isDebugEnabled();
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
try {
//从request中解析PreAuthenticatedAuthenticationToken(注意这里并不是OAuth2Authentication)
Authentication authentication = this.tokenExtractor.extract(request);
if(authentication == null) {
if(this.stateless && this.isAuthenticated()) {
if(debug) {
logger.debug("Clearing security context.");
}
SecurityContextHolder.clearContext();
}
if(debug) {
logger.debug("No token in request, will continue chain.");
}
} else {
request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, authentication.getPrincipal());
if(authentication instanceof AbstractAuthenticationToken) {
AbstractAuthenticationToken needsDetails = (AbstractAuthenticationToken)authentication;
needsDetails.setDetails(this.authenticationDetailsSource.buildDetails(request));
}
Authentication authResult = this.authenticationManager.authenticate(authentication);
if(debug) {
logger.debug("Authentication success: " + authResult);
}
this.eventPublisher.publishAuthenticationSuccess(authResult);
//此处为把authResult放入安全容器中,此处比较重要
SecurityContextHolder.getContext().setAuthentication(authResult);
}
} catch (OAuth2Exception var9) {
SecurityContextHolder.clearContext();
if(debug) {
logger.debug("Authentication request failed: " + var9);
}
this.eventPublisher.publishAuthenticationFailure(new BadCredentialsException(var9.getMessage(), var9), new PreAuthenticatedAuthenticationToken("access-token", "N/A"));
this.authenticationEntryPoint.commence(request, response, new InsufficientAuthenticationException(var9.getMessage(), var9));
return;
}
chain.doFilter(request, response);
}
TokenExtractor也是一个接口,我们可以看到,他是由BearerTokenExtractor实现类来实现的.基本上BearerTokenExtractor整个对象的方法都有调用.
public class BearerTokenExtractor implements TokenExtractor {
private static final Log logger = LogFactory.getLog(BearerTokenExtractor.class);
public BearerTokenExtractor() {
}
public Authentication extract(HttpServletRequest request) {
String tokenValue = this.extractToken(request);
if(tokenValue != null) {
PreAuthenticatedAuthenticationToken authentication = new PreAuthenticatedAuthenticationToken(tokenValue, "");
return authentication;
} else {
return null;
}
}
/**
*从request参数查找认证
*/
protected String extractToken(HttpServletRequest request) {
String token = this.extractHeaderToken(request);
if(token == null) {
logger.debug("Token not found in headers. Trying request parameters.");
token = request.getParameter("access_token");
if(token == null) {
logger.debug("Token not found in request parameters. Not an OAuth2 request.");
} else {
request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_TYPE, "Bearer");
}
}
return token;
}
/**
*从request的header开始查找认证
*/
protected String extractHeaderToken(HttpServletRequest request) {
Enumeration headers = request.getHeaders("Authorization");
String value;
do {
if(!headers.hasMoreElements()) {
return null;
}
value = (String)headers.nextElement();
} while(!value.toLowerCase().startsWith("Bearer".toLowerCase()));
String authHeaderValue = value.substring("Bearer".length()).trim();
request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_TYPE, value.substring(0, "Bearer".length()).trim());
int commaIndex = authHeaderValue.indexOf(44);
if(commaIndex > 0) {
authHeaderValue = authHeaderValue.substring(0, commaIndex);
}
return authHeaderValue;
}
}
SecurityContextHolder.getContext().setAuthentication(authResult);我们单独把这个提取出来,在之前的
@GetMapping("/user-me")
public Authentication principal() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
log.debug("user-me:{}", authentication.getName());
return authentication;
}
我们可以看到我们访问的登录验证用户是从SecurityContextHolder.getContext().getAuthentication()提取出来的.