我使用spring boot,spring security oauth2存储令牌jdbc。但是我访问oauth / token时遇到问题。它总是让我出错:
"error": "Unauthorized",
"message": "Unauthorized",
"path": "/oauth/token"
我的项目如下:
WebSecurityConfig.class
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
class WebSecurityConfig : WebSecurityConfigurerAdapter() {
@Autowired
private val dataSource: DataSource? = null
@Value("\${security.signing-key}")
private val signingKey: String? = null
@Value("\${security.encoding-strength}")
private val encodingStrength: Int? = null
@Value("\${security.security-realm}")
private val securityRealm: String? = null
@Bean
@Throws(Exception::class)
override fun authenticationManager(): AuthenticationManager {
return super.authenticationManager()
}
@Bean
fun passwordEncoder(): BCryptPasswordEncoder {
return BCryptPasswordEncoder()
}
@Throws(Exception::class)
override fun configure(http: HttpSecurity) {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable()
.authorizeRequests()
.antMatchers("/auth/signup").permitAll()
.antMatchers("/oauth/token").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic()
.realmName(securityRealm)
}
@Bean
fun tokenStore(): JdbcTokenStore {
return JdbcTokenStore(dataSource)
}
@Bean
fun accessTokenConverter(): JwtAccessTokenConverter {
val converter = JwtAccessTokenConverter()
converter.setSigningKey(signingKey!!)
return converter
}
@Bean
@Primary //Making this primary to avoid any accidental duplication with another token service instance of the same name
fun tokenServices(): DefaultTokenServices {
val defaultTokenServices = DefaultTokenServices()
defaultTokenServices.setTokenStore(tokenStore())
defaultTokenServices.setSupportRefreshToken(true)
return defaultTokenServices
}
@Bean
@Throws(Exception::class)
override fun authenticationManagerBean(): AuthenticationManager {
return super.authenticationManagerBean()
}
}
AuthorizationServerConfig.class
@Configuration
@EnableAuthorizationServer
class AuthorizationServerConfig : AuthorizationServerConfigurerAdapter() {
@Value("\${security.jwt.client-id}")
private val clientId: String? = null
@Value("\${security.jwt.client-secret}")
private val clientSecret: String? = null
@Value("\${security.jwt.grant-type}")
private val grantType: String? = null
@Value("\${security.jwt.scope-read}")
private val scopeRead: String? = null
@Value("\${security.jwt.scope-write}")
private val scopeWrite = "write"
@Value("\${security.jwt.resource-ids}")
private val resourceIds: String? = null
@Autowired
private val tokenStore: TokenStore? = null
@Autowired
private val accessTokenConverter: JwtAccessTokenConverter? = null
@Autowired
private val authenticationManager: AuthenticationManager? = null
@Autowired
private val passwordEncoder: PasswordEncoder? = null
@Autowired
private val dataSource: DataSource? = null
@Throws(Exception::class)
override fun configure(configurer: ClientDetailsServiceConfigurer) {
configurer.jdbc(dataSource);
}
@Throws(Exception::class)
override fun configure(endpoints: AuthorizationServerEndpointsConfigurer) {
val enhancerChain = TokenEnhancerChain()
enhancerChain.setTokenEnhancers(Arrays.asList<TokenEnhancer>(accessTokenConverter!!))
endpoints.tokenStore(tokenStore)
.accessTokenConverter(accessTokenConverter)
.tokenEnhancer(enhancerChain)
.authenticationManager(authenticationManager)
}
UserDetailsService
@Service
class UserDetailsServiceImpl : UserDetailsService {
@Autowired
lateinit var userRepository: UserRepository
@Throws(UsernameNotFoundException::class)
override fun loadUserByUsername(username: String): UserDetails {
val user = userRepository.findByUsername(username).get()
?: throw UsernameNotFoundException("User '${username} not found")
val authorities: List<GrantedAuthority> = user.roles!!.stream().map({ role -> SimpleGrantedAuthority(role.name) }).collect(Collectors.toList<GrantedAuthority>())
return org.springframework.security.core.userdetails.User
.withUsername(username)
.password(user.password)
.authorities(authorities)
.accountExpired(false)
.accountLocked(false)
.credentialsExpired(false)
.disabled(false)
.build()
}
}
UserRepository
interface UserRepository : JpaRepository<User, Long> {
fun existsByUsername(@Param("username") username: String): Boolean
fun findByUsername(@Param("username") username: String): Optional<User>
fun findByEmail(@Param(value = "email") email: String): Optional<User>
fun deleteByUsername(@Param("username") username: String)
}
资源服务配置
@Configuration
@EnableResourceServer
class ResourceServerConfig : ResourceServerConfigurerAdapter() {
@Autowired
private val tokenServices: ResourceServerTokenServices? = null
@Value("\${security.jwt.resource-ids}")
private val resourceIds: String? = null
@Throws(Exception::class)
override fun configure(resources: ResourceServerSecurityConfigurer) {
resources.resourceId(resourceIds).tokenServices(tokenServices)
}
@Throws(Exception::class)
override fun configure(http: HttpSecurity) {
http
.requestMatchers()
.and()
.authorizeRequests()
.antMatchers("/actuator/**", "/api-docs/**").permitAll()
.antMatchers("/springjwt/**").authenticated()
}
}
SQL中的数据表用户
Data Table oauth_client_details
邮递员请求:
当我请求http://localhost:8989/oauth/token时,它总是抛出异常:
{
"timestamp": "2019-11-18T18:15:51.084+0000",
"status": 401,
"error": "Unauthorized",
"message": "Unauthorized",
"path": "/oauth/token"
}
我不明白为什么。请帮助我
答案 0 :(得分:0)
您是否尝试过覆盖AuthorizationServerConfig.class中的configure
方法,如下所示:
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer.passwordEncoder(this.passwordEncoder)
.allowFormAuthenticationForClients();
}
这是Java代码,对于kotlin,它是这样的:
override fun configure(oauthServer: AuthorizationServerSecurityConfigurer) {
oauthServer.passwordEncoder(passwordEncoder)
.allowFormAuthenticationForClients()
}
我认为您忘记在AuthorizationServerConfig类中设置passwordEncoder。
此外,请尝试使用allowFormAuthenticationForClients()
。通过启用表单参数而不是基本身份验证,可以对客户端进行身份验证。
最后,尝试使用类似Request access token的请求