oauth2 认证服务器 资源服务器分离 使用Redis存储To
2019-08-08 本文已影响0人
BananaNo1
Spring boot 版本 2.0.3.RELEASE
Spring Cloud 版本 Finchley.RELEASE
// 不使用Spring Cloud 可以不引入相关配置
Auth 项目
pom maven 引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
// 版本低了使用 redis保存token 有bug
// error : org.springframework.data.redis.connection.RedisConnection.set([B[B)V
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
yml 配置
# redis 换成自己配置
spring:
redis:
host:
port: 6379
password:
database:
# 注册进入 eureka
eureka:
client:
service-url:
defaultZone: http://localhost:8081/eureka
instance:
instance-id: auth
prefer-ip-address: true
认证服务器配置 auth 项目
继承AuthorizationServerConfigurerAdapter
重写相关配置
@Configuration
@EnableAuthorizationServer //认证服务器
public class AuthenticationConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Autowired
private MyUserDetailsService myUserDetailsService;
@Autowired
private PasswordEncoder passwordEncoder;
@Bean
public RedisTokenStore tokenStore() {
RedisTokenStore tokenStore = new RedisTokenStore(redisConnectionFactory);
tokenStore.setPrefix("user-token:");
return tokenStore;
}
/* // 对生成的token进行二次处理
@Bean
public TokenEnhancer tokenEnhancer() {
return new RedisTokenEnhancer();
}
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
// 开启/oauth/token_key验证端口无权限访问
.tokenKeyAccess("permitAll()")
// 开启/oauth/check_token验证端口认证权限访问
.checkTokenAccess("permitAll()")
// 开启后请求需要带上 client_id client_secret 不需要 Basic 请求头
// 默认请求头 Basic Base64(client_id+client_secret)
.allowFormAuthenticationForClients();
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 内存方式存储
clients.inMemory()
.withClient("app")
.secret(passwordEncoder.encode("123456"))
.scopes("app")
.authorizedGrantTypes("password", "refresh_token");
// 认证支持类型
}
// 生成token的处理
@Primary
@Bean
public DefaultTokenServices defaultTokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore());
// 是否支持 refreshToken
tokenServices.setSupportRefreshToken(true);
// 是否复用 refreshToken
tokenServices.setReuseRefreshToken(true);
// tokenServices.setTokenEnhancer(tokenEnhancer());
// token有效期自定义设置,默认12小时
tokenServices.setAccessTokenValiditySeconds(60 * 60 * 12);
//默认30天,这里修改
tokenServices.setRefreshTokenValiditySeconds(60 * 60 * 24 * 7);
return tokenServices;
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
//.tokenEnhancer(tokenEnhancer())
.tokenStore(tokenStore())
.userDetailsService(myUserDetailsService)
.authenticationManager(authenticationManager)
.tokenServices(defaultTokenServices());
}
}
security
配置
@Configuration
@EnableWebSecurity
public class BasicSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 用户登录处理逻辑
*
* @return
*/
@Override
public UserDetailsService userDetailsService() {
return new MyUserDetailsService();
}
/**
* 加密器
*
* @return
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.anyRequest().authenticated()
.and()
.httpBasic();
}
}
MyUserDetailsService
用户登录验证逻辑和权限处理
@Service
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
// @Autowired
// private UserContext userContext;
@Autowired
private TbUserService tbUserService;
@Autowired
private TbPermissionMapper tbPermissionMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
/*
// 从数据库验证用户密码 查询用户权限
// rabc
TbUser tbUser = tbUserService.getByUsername(username);
List<GrantedAuthority> grantedAuthorities = Lists.newArrayList();
if (tbUser != null) {
List<TbPermission> tbPermissions = tbPermissionMapper.selectByUserId(tbUser.getId());
tbPermissions.stream().forEach(tbPermission -> {
if (tbPermission != null && tbPermission.getEnname() != null) {
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(tbPermission.getEnname());
grantedAuthorities.add(grantedAuthority);
}
});
}
return new User(tbUser.getUsername(), tbUser.getPassword(), grantedAuthorities);
*/
// 逻辑用户名随便输入 只要密码是123456 即可登录系统并拥有admin权限
if (username != null) {
return new User(username, this.passwordEncoder.encode("123456"),
AuthorityUtils.createAuthorityList("admin"));
} else {
throw new UsernameNotFoundException("用户[" + username + "]不存在");
}
}
}
Resource 项目
版本和Auth一样
pom maven 引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
yml配置
和Auth项目类似 引入 redis
根据自己需要是否使用eureka
Resource 配置
继承ResourceServerConfigurerAdapter
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Bean
public RedisTokenStore tokenStore() {
RedisTokenStore tokenStore = new RedisTokenStore(redisConnectionFactory);
tokenStore.setPrefix("user-token:");
return tokenStore;
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic();
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore());
}
}
security
配置
@Configuration
@EnableWebSecurity
// @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true) // 权限验证注解
public class BasicSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.anyRequest().authenticated()
.and()
.httpBasic()
.and().csrf().disable();
}
}
暴露 资源
@RestController
@RequestMapping("/user")
public class TestController {
@GetMapping("/hello")
// @PreAuthorize("hasAuthority('System')") // 验证权限
public String hello() {
return "hello xxx ";
}
}
测试
-
获取token
获取token.png
2.查看Redis 是否生成token
查看Redis Token.png
3.请求资源
请求资源服务器.png