oauth入门
认证服务器
依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-security</artifactId> <version>2.2.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> <version>2.2.5.RELEASE</version> </dependency>
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <scope>test</scope> </dependency>
|
认证服务器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| package cn.sdadgz.oauth;
import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices; import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
@Configuration @EnableAuthorizationServer @RequiredArgsConstructor public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {
private final AuthorizationCodeServices authorizationCodeServices; private final AuthenticationManager authenticationManager; private final UserDetailsService userDetailsService; private final AuthorizationServerTokenServices tokenServices; private final PasswordEncoder passwordEncoder;
@Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("client1") .secret(passwordEncoder.encode("123456")) .resourceIds("/test") .authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token") .scopes("all") .autoApprove(false) .redirectUris("https://sdadgz.cn"); }
@Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .authenticationManager(authenticationManager) .userDetailsService(userDetailsService) .authorizationCodeServices(authorizationCodeServices) .tokenServices(tokenServices) .allowedTokenEndpointRequestMethods(HttpMethod.POST); }
@Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security .tokenKeyAccess("permitAll()") .checkTokenAccess("permitAll()") .allowFormAuthenticationForClients(); }
}
|
token存储
uuid存储
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| package cn.sdadgz.oauth;
import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
@Configuration @RequiredArgsConstructor public class TokenConfig {
@Bean public TokenStore tokenStore() { return new InMemoryTokenStore(); }
}
|
jwt存储
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| package cn.sdadgz.oauth;
import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
@Configuration @RequiredArgsConstructor public class TokenConfig { public static final String SIGN_KEY = "password";
@Bean public TokenStore tokenStore(){ return new JwtTokenStore(accessTokenConverter()); }
@Bean public JwtAccessTokenConverter accessTokenConverter(){ JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey(SIGN_KEY); return converter; }
}
|
UserDetails用户
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| package cn.sdadgz.oauth;
import cn.hutool.extra.spring.SpringUtil; import lombok.NoArgsConstructor; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.crypto.password.PasswordEncoder;
import java.util.Collection;
@NoArgsConstructor public class OauthUser implements UserDetails {
private static final PasswordEncoder passwordEncoder = SpringUtil.getBean(PasswordEncoder.class);
@Override public Collection<? extends GrantedAuthority> getAuthorities() { return null; }
@Override public String getPassword() { return passwordEncoder.encode("123456"); }
@Override public String getUsername() { return "root"; }
@Override public boolean isAccountNonExpired() { return true; }
@Override public boolean isAccountNonLocked() { return true; }
@Override public boolean isCredentialsNonExpired() { return true; }
@Override public boolean isEnabled() { return true; } }
|
UserDetialsService用户查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package cn.sdadgz.oauth;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service;
@Service public class UserDetailsServiceImpl implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return new OauthUser(); } }
|
WebsecurityConfig安全配置
正常配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| package cn.sdadgz.oauth;
import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.provider.ClientDetailsService; import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices; import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices; import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; import org.springframework.security.oauth2.provider.token.DefaultTokenServices; import org.springframework.security.oauth2.provider.token.TokenStore;
@Configuration @RequiredArgsConstructor public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final TokenStore tokenStore; private final ClientDetailsService clientDetailsService;
@Bean public AuthorizationServerTokenServices tokenServices() { DefaultTokenServices defaultTokenServices = new DefaultTokenServices(); defaultTokenServices.setClientDetailsService(clientDetailsService); defaultTokenServices.setSupportRefreshToken(true); defaultTokenServices.setTokenStore(tokenStore); defaultTokenServices.setAccessTokenValiditySeconds(5673); defaultTokenServices.setRefreshTokenValiditySeconds(123456); return defaultTokenServices; }
@Bean public AuthorizationCodeServices authorizationCodeServices(){ return new InMemoryAuthorizationCodeServices(); }
@Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); }
@Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); }
@Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .anyRequest().authenticated() .and() .formLogin(); } }
|
jwt配置
defaultTokenServices.setTokenStore(tokenStore);后面加上
defaultTokenServices.setTokenEnhancer(accessTokenConverter);
资源服务器
ResourceServerConfig资源服务器配置
正常配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| package cn.sdadgz.resourceServer;
import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
@EnableResourceServer @Configuration @RequiredArgsConstructor public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private final ResourceServerTokenServices tokenService;
@Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources .resourceId("/test") .tokenServices(tokenService) .stateless(true); }
@Override public void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/**") .access("#oauth2.hasScope('all')") .and().csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); } }
|
jwt配置
注释掉.tokenServices(tokenService),加上
.tokenStore(tokenStore)
WebSecurity安全配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| package cn.sdadgz.resourceServer;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.oauth2.provider.token.RemoteTokenServices; import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
@Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean public ResourceServerTokenServices tokenServices(){ RemoteTokenServices services = new RemoteTokenServices(); services.setCheckTokenEndpointUrl("http://localhost:30002/oauth/check_token"); services.setClientId("client1"); services.setClientSecret("123456"); return services; }
@Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/test/**") .authenticated() .anyRequest().permitAll(); } }
|
认证模式
client_credentials客户端模式
不安全,内部系统使用
1
| {{base_url}}/oauth/token?client_id=client1&client_secret=123456&grant_type=client_credentials
|
password密码模式
安全了一点,还是内部