概述:新版本的Spring OAuth2.0 ,不再作为一个独立模块,而是Spring Security中的一个子模块。OAuth2提供项目安全认证(包括身份,权限,角色认证等)。
其中OAuth2为我们提供了四种授权方式:
授权码模式(authorization code)
简化模式(implicit)
密码模式(resource owner password credentials)
客户端模式(client credentials)
而较常用的则为密码模式和授权码模式,而授权码模式又是最为安全的模式,常见的第三方授权登录就是基于Oauth2标准。完整的项目结构分为:客户端服务,认证服务,资源服务。客户端需要访问资源服务的资源时,则需要得到认证服务的认证。
一、引依赖
<!-- nacos 作为服务注册中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- nacos 作为配置中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.5.RELEASE</version>
</dependency>
二、配置认证服务器
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Resource
private AuthenticationManager authenticationManager;
@Resource
private DataSource dataSource;
@Autowired
private WebResponseExceptionTranslator webResponseExceptionTranslator;
@Autowired
private IntegrationAuthenticationFilter integrationAuthenticationFilter;
@Autowired
private IntegrationUserDetailsService integrationUserDetailsService;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(new JdbcClientDetailsService(dataSource));
}
@Bean
public MyRedisTokenStore myRedisTokenStore() {
return new MyRedisTokenStore(redisConnectionFactory);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.tokenStore(myRedisTokenStore())
.authenticationManager(authenticationManager)
.exceptionTranslator(webResponseExceptionTranslator)
.userDetailsService(integrationUserDetailsService)
.reuseRefreshTokens(false);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients()
.tokenKeyAccess("isAuthenticated()")
.checkTokenAccess("permitAll()")
.addTokenEndpointAuthenticationFilter(integrationAuthenticationFilter);
}
}
WebSecurity 配置
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
public void configure(HttpSecurity http) throws Exception {
// 版本不同可能顺序不同Can't configure antMatchers after anyRequest
http.requestMatchers()
.antMatchers("/login", "/oauth/authorize")
.and()
.authorizeRequests().antMatchers("/static/**")
.permitAll()
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.authorizeRequests()
.anyRequest().authenticated();
}
}
登录用户自定义过滤
@Component
public class OauthUserDetailsService implements UserDetailsService {
protected final Log logger = LogFactory.getLog(getClass());
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(final String username)
throws UsernameNotFoundException {
User user = userRepository.findByUserName(username);
logger.info("loadUserByUsername username=" + username);
// 如果用户不存在则认证失败
if(user == null){
throw new UsernameNotFoundException(username + " not found");
}
// 注意:此处的密码记得要进行加密,因为在前面配置的时候是使用了 MD5 加密,所以这里也要进行加密
return new OauthUserInfo(username, MD5Util.encodeMD5(user.getPassword()),user.getRole());
}
}
以上只是将主要的配置附上,还有 user 表以及 集成 mybatis 等步骤没有写出,这里涉及到Feign的调用。注意:user 对象需要实现 Serializable 接口(可序列化),因为在认证的时候该对象是需要进行IO操作的。
三、配置资源服务器
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable()//禁用了csrf(跨站请求伪造)功能
.authorizeRequests()//限定签名成功的请求
//必须认证过后才可以访问;注意:hasAnyRole 会默认加上ROLE_前缀,而hasAuthority不会加前缀
.antMatchers("/decision/**","/govern/**").hasAnyRole("user") // 在角色过滤的时候需要注意user角色需要加角色前缀
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/test/**").authenticated()
// 免验证请求
.antMatchers("/oauth/**").permitAll();
}
}
这个类表明了此应用是OAuth2 的资源服务器,此处主要指定受资源服务器保护的资源链接 默认情况下spring security oauth2的http配置会被WebSecurityConfigurerAdapter的配置覆盖