开启认证服务器
@Configuration
@EnableAuthorizationServer
public class ImoocAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private TokenStore tokenStore;
@Autowired(required = false)
private JwtAccessTokenConverter jwtAccessTokenConverter;
@Autowired(required = false)
private TokenEnhancer jwtTokenEnhancer;
@Autowired
private SecurityProperties securityProperties;
/**
* 认证及token配置
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore)
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
if (jwtAccessTokenConverter != null && jwtTokenEnhancer != null) {
TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
List<TokenEnhancer> enhancers = new ArrayList<>();
enhancers.add(jwtTokenEnhancer);
enhancers.add(jwtAccessTokenConverter);
enhancerChain.setTokenEnhancers(enhancers);
endpoints.tokenEnhancer(enhancerChain).accessTokenConverter(jwtAccessTokenConverter);
}
}
/**
* tokenKey的访问权限表达式配置
*/
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()");
}
/**
* 客户端配置
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
InMemoryClientDetailsServiceBuilder builder = clients.inMemory();
if (ArrayUtils.isNotEmpty(securityProperties.getOauth2().getClients())) {
for (OAuth2ClientProperties client : securityProperties.getOauth2().getClients()) {
builder.withClient(client.getClientId())
.secret(client.getClientSecret())
.authorizedGrantTypes("refresh_token", "authorization_code", "password")
.accessTokenValiditySeconds(client.getAccessTokenValidateSeconds())
.refreshTokenValiditySeconds(2592000)
.scopes("all");
}
}
}
}
官方参数:
4.1.1. Authorization Request
The client constructs the request URI by adding the following
parameters to the query component of the authorization endpoint URI
using the "application/x-www-form-urlencoded" format, per Appendix B:
response_type
REQUIRED. Value MUST be set to "code".
client_id
REQUIRED. The client identifier as described in Section 2.2. 不配置,会打印出来
redirect_uri
OPTIONAL. As described in Section 3.1.2.
scope
OPTIONAL. The scope of the access request as described by
Section 3.3.
state
RECOMMENDED. An opaque value used by the client to maintain
state between the request and callback. The authorization
server includes this value when redirecting the user-agent back
to the client. The parameter SHOULD be used for preventing
cross-site request forgery as described in Section 10.12.
imooc.security.oauth2.clients[0].clientId = imooc 第一次配置去掉[0]
imooc.security.oauth2.clients[0].clientSecret = imoocsecret
上一步请求,通过后,点同意授权,获得授权码
4.1.3. Access Token Request
The client makes a request to the token endpoint by sending the
following parameters using the "application/x-www-form-urlencoded"
format per Appendix B with a character encoding of UTF-8 in the HTTP
request entity-body:
grant_type
REQUIRED. Value MUST be set to "authorization_code".
code
REQUIRED. The authorization code received from the
authorization server.
redirect_uri
REQUIRED, if the "redirect_uri" parameter was included in the
authorization request as described in Section 4.1.1, and their
values MUST be identical.
client_id
REQUIRED, if the client is not authenticating with the
authorization server as described in Section 3.2.1.
If the client type is confidential or the client was issued client
credentials (or assigned other authentication requirements), the
client MUST authenticate with the authorization server as described
in Section 3.2.1.
For example, the client makes the following HTTP request using TLS
(with extra line breaks for display purposes only):
密码模式: 自己公司扮演app,自己公司扮演提供商 可用
资源服务器
@Configuration
@EnableResourceServer
public class ImoocResourceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
protected AuthenticationSuccessHandler imoocAuthenticationSuccessHandler;
@Autowired
protected AuthenticationFailureHandler imoocAuthenticationFailureHandler;
@Autowired
private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;
@Autowired
private OpenIdAuthenticationSecurityConfig openIdAuthenticationSecurityConfig;
@Autowired
private ValidateCodeSecurityConfig validateCodeSecurityConfig;
@Autowired
private SpringSocialConfigurer imoocSocialSecurityConfig;
@Autowired
private AuthorizeConfigManager authorizeConfigManager;
@Autowired
private FormAuthenticationConfig formAuthenticationConfig;
@Override
public void configure(HttpSecurity http) throws Exception {
formAuthenticationConfig.configure(http);
http.apply(validateCodeSecurityConfig)
.and()
.apply(smsCodeAuthenticationSecurityConfig)
.and()
.apply(imoocSocialSecurityConfig)
.and()
.apply(openIdAuthenticationSecurityConfig)
.and()
.csrf().disable();
authorizeConfigManager.config(http.authorizeRequests());
}
}
需要加上token_type 和 token
源码解析
自定义 如短信登录,申请token
/**
* APP环境下认证成功处理器
*/
@Component("imoocAuthenticationSuccessHandler")
public class ImoocAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
//AuthenticationSuccessHandler
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private ObjectMapper objectMapper;
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
private AuthorizationServerTokenServices authorizationServerTokenServices;
@SuppressWarnings("unchecked")
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
logger.info("登录成功");
String header = request.getHeader("Authorization");
if (header == null || !header.startsWith("Basic ")) {
throw new UnapprovedClientAuthenticationException("请求头中无client信息");
}
String[] tokens = extractAndDecodeHeader(header, request);
assert tokens.length == 2;
String clientId = tokens[0];
String clientSecret = tokens[1];
ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
if (clientDetails == null) {
throw new UnapprovedClientAuthenticationException("clientId对应的配置信息不存在:" + clientId);
} else if (!StringUtils.equals(clientDetails.getClientSecret(), clientSecret)) {
throw new UnapprovedClientAuthenticationException("clientSecret不匹配:" + clientId);
}
TokenRequest tokenRequest = new TokenRequest(MapUtils.EMPTY_MAP, clientId, clientDetails.getScope(), "custom");
OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);
OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);
OAuth2AccessToken token = authorizationServerTokenServices.createAccessToken(oAuth2Authentication);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(token));
}
private String[] extractAndDecodeHeader(String header, HttpServletRequest request) throws IOException {
byte[] base64Token = header.substring(6).getBytes("UTF-8");
byte[] decoded;
try {
decoded = Base64.decode(base64Token);
} catch (IllegalArgumentException e) {
throw new BadCredentialsException("Failed to decode basic authentication token");
}
String token = new String(decoded, "UTF-8");
int delim = token.indexOf(":");
if (delim == -1) {
throw new BadCredentialsException("Invalid basic authentication token");
}
return new String[] { token.substring(0, delim), token.substring(delim + 1) };
}
}