本文记录一下使用SpringSecurityOAuth2配置自定义Token实现OAuth2授权的步骤
1、相关知识
2、构建项目
本文使用的springboot版本是2.0.4.RELEASE,不同版本可能会有所区别。下面是主要的配置文件和类:
1)pom依赖
org.springframework.boot
spring-boot-starter-security
org.springframework.security.oauth.boot
spring-security-oauth2-autoconfigure
2.1.3.RELEASE
2)application.properties
#不需要,暂时写死在代码中,重构时移植到此处即可
3)主配置类
@EnableWebSecurity
@Configurationpublic class WebSecurityConfig extendsWebSecurityConfigurerAdapter{
@Overrideprotected void configure(HttpSecurity http) throwsException {
http.httpBasic().and().csrf().disable();
}
@Bean("authenticationManager")public AuthenticationManager authenticationManagerBean() throwsException {return super.authenticationManagerBean();
}
@BeanpublicPasswordEncoder passwordEncoder() {return newBCryptPasswordEncoder();
}
}
4)用户认证类
@Component
public class MyUserDetailsService implementsUserDetailsService{
@AutowiredprivatePasswordEncoder passwordEncoder;
@Overridepublic UserDetails loadUserByUsername(String username) throwsUsernameNotFoundException {
System.out.println("登录用户名:"+username);
String password= passwordEncoder.encode("123456");return new User(username,password,true,true,true,true,
AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_USER"));
}
}
5)认证服务类
@Configuration
@EnableAuthorizationServerpublic class AuthorizationServerConfig extendsAuthorizationServerConfigurerAdapter{
@AutowiredprivateAuthenticationManager authenticationManager;
@AutowiredprivateUserDetailsService userDetailsService;
@AutowiredprivatePasswordEncoder passwordEncoder;
@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throwsException {
endpoints
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throwsException {
clients
.inMemory()//Token保存在内存中
.withClient("MyProject").secret(passwordEncoder.encode("MyProject_123"))//指明client-id和client-secret
.accessTokenValiditySeconds(7200)//令牌有效时间,单位秒
.authorizedGrantTypes("refresh_token","password","authorization_code")//支持刷新令牌、密码模式、授权码模式
.scopes("all","read","write")//权限有哪些,如果这两配置了该参数,客户端发请求可以不带参数,使用配置的参数
.redirectUris("http://127.0.0.1:8080/login");
}
}
说明:
a)client-secret必须加密,否则在后面测试中,总是弹出让输入用户名、密码。
b)代码中配置了权限,客户端可以不携带scopes参数,如果携带必须是all、read、write或者其组合。
c)使用授权码模式,必须配置redirectUris,使用密码模式可以不配置,去掉该语句即可。
6)启动类
@SpringBootApplicationpublic classApp {public static voidmain(String[] args) {
SpringApplication.run(App.class, args);
}
}
3、测试验证
1)验证默认scope情况获取Token
2)验证指定scope情况获取Token
说明:
a)发送参数是all write,返回scope是all write
b)发送参数是write read,返回scope是read write
c)发送除了all read write以外的任何scope值,都返回"Invalid scope",不能用逗号分隔。
3)验证授权码模式
b)输入用户名任意,密码123456
c)点击Authorize,浏览器跳转如下地址,授权码为GPLd04
d)获取Token
4、给多个应用发送Token
修改认证服务类中configure方法,如下,模拟给两个应用发送令牌:
@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throwsException {
InMemoryClientDetailsServiceBuilder builder=clients.inMemory();
List list = new ArrayList();
String app1= "MyProject,MyProject_123,7200";
String app2= "Test,Test123,10";
list.add(app1);
list.add(app2);
String client= "";
String secret= "";intaccessTokenValiditySeconds;for(String str:list) {
client= str.split(",")[0];
secret= str.split(",")[1];
accessTokenValiditySeconds= Integer.valueOf(str.split(",")[2]);
builder.withClient(client).secret(passwordEncoder.encode(secret))
.accessTokenValiditySeconds(accessTokenValiditySeconds)
.refreshTokenValiditySeconds(2592000)
.authorizedGrantTypes("refresh_token","password")
.scopes("all","read","write");
}
}
5、使用Redis存储Token
使用Redis存储Token,当应用重启后,Token不会改变。
1)引入Redis依赖,并添加配置
org.springframework.boot
spring-boot-starter-data-redis
spring.redis.host = 192.168.7.151spring.redis.port= 637
2)配置TokenStore为Redis
@Configurationpublic classTokenStoreConfig {
@AutowiredprivateRedisConnectionFactory redisConnectionFactory;
@BeanpublicTokenStore redisTokenStore() {return newRedisTokenStore(redisConnectionFactory);
}
}
3)修改认证服务类中configure方法,给endpoints指定Token存储方式为Redis
@AutowiredprivateTokenStore tokenStore;
@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throwsException {
endpoints
.tokenStore(tokenStore)
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
4)演示,初始时候Redis的key为空,当Rest插件请求一次Token后,Redis中写入了数据。重启应用再访问,Token不改变。