2019独角兽企业重金招聘Python工程师标准>>>
假设我们的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()提取出来的.