Spring Cloud OAuth2中访问/oauth/token报server_error问题的解决

Spring Cloud OAuth2中访问/oauth/token报server_error问题的解决

问题分析

在新建的Spring Cloud OAuth2项目中使用grant_type为password方式访问时报server_error。在postman中如下图:

{
    "error": "server_error",
    "error_description": "Internal Server Error"
}

如下图:
在这里插入图片描述
java后台报错如下:

2021-01-16 17:59:35.149  WARN 11200 --- [nio-5002-exec-2] o.s.s.o.provider.endpoint.TokenEndpoint  : Handling error: NestedServletException, Handler dispatch failed; nested exception is java.lang.StackOverflowError

这个问题是由于grant_type=password代表的用户名密码授权,需要指定UserDetailsService才行。

问题解决

1、定义Role类实现GrantedAuthority接口、定义User类实现UserDetails, Serializable接口,如下:
Role.java

package com.wongoing.oauth2.entity;

import org.springframework.security.core.GrantedAuthority;

public class Role implements GrantedAuthority {
	
	private Long id;
	private String name;
	
	
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return name;
	}
	
	@Override
	public String getAuthority() {
		// TODO Auto-generated method stub
		return name;
	}
}

User.java

package com.wongoing.oauth2.entity;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

public class User implements UserDetails, Serializable {

	private Long id;
	private String username;
	private String password;
	private List<Role> authorities;
	

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public void setAuthorities(List<Role> authorities) {
		this.authorities = authorities;
	}

	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		// TODO Auto-generated method stub
		return this.authorities;
	}

	@Override
	public String getPassword() {
		// TODO Auto-generated method stub
		return this.password;
	}

	@Override
	public String getUsername() {
		// TODO Auto-generated method stub
		return this.username;
	}

	@Override
	public boolean isAccountNonExpired() {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public boolean isAccountNonLocked() {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public boolean isEnabled() {
		// TODO Auto-generated method stub
		return true;
	}
}

2、增加UserDetailsService实现类,如下:

package com.wongoing.oauth2.config;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import com.wongoing.oauth2.entity.Role;
import com.wongoing.oauth2.entity.User;

@Component
public class OAuth2UserDetailsService implements UserDetailsService {

	@Autowired
	private PasswordEncoder passwordEncoder;
	
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		//以下代码可以通过注入UserDao实现从数据库中检索用户信息,这里为了测试方便直接指定了2个用户
		if ("admin".equals(username)) {
			Role role = new Role();
			role.setId(1L);;
			role.setName("管理员");
			
			List<Role> authorities = new ArrayList<Role>();
			authorities.add(role);
			
			User entity = new User();
			entity.setId(1L);
			entity.setUsername("admin");
			entity.setPassword(this.passwordEncoder.encode("123456"));
			entity.setAuthorities(authorities);
			
			return entity;
		}
		if ("zhenglb".equals(username)) {
			Role role = new Role();
			role.setId(1L);;
			role.setName("管理员");
			
			List<Role> authorities = new ArrayList<Role>();
			authorities.add(role);
			
			User entity = new User();
			entity.setId(1L);
			entity.setUsername("zhenglb");
			entity.setPassword(this.passwordEncoder.encode("pwd"));
			entity.setAuthorities(authorities);
			
			return entity;
		}
		return null;
	}
}

3、在AuthorizationServerConfigurerAdapter实现类中注入UserDetailsService,并使用,代码如下:

package com.wongoing.oauth2.config;

import org.springframework.beans.factory.annotation.Autowired;
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.bcrypt.BCryptPasswordEncoder;
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.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;

@Configuration
@EnableAuthorizationServer
public class OAuth2ServerConfig extends AuthorizationServerConfigurerAdapter {

	private TokenStore tokenStore = new InMemoryTokenStore();
	
	@Autowired
	private PasswordEncoder passwordEncoder;
	
	@Autowired
	private AuthenticationManager authenticationManager;
	
	@Autowired
	private UserDetailsService userDetailsService;
	
	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {		
		clients.inMemory().withClient("client_1").secret(this.passwordEncoder.encode("123456"))
			.authorizedGrantTypes("password")
			.scopes("all");
	}
	
	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
		
		endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
		
		// 配置Token的存储方式
		endpoints.tokenStore(tokenStore)
			// 注入WebSecurityConfig配置的bean
			.authenticationManager(authenticationManager)
			// 读取用户的验证信息
			.userDetailsService(userDetailsService);
	}
	
	@Override
	public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
		// 对获取Token的请求不再拦截
		oauthServer
			.tokenKeyAccess("permitAll()")
			// 验证获取Token的验证信息
			.checkTokenAccess("isAuthenticated()")
			//这个如果配置支持allowFormAuthenticationForClients的,且对/oauth/token请求的参数中有client_id和client-secret的会走ClientCredentialsTokenEndpointFilter来保护
			//如果没有支持allowFormAuthenticationForClients或者有支持但对/oauth/token请求的参数中没有client_id和client_secret的,走basic认证保护
			.allowFormAuthenticationForClients();
	}
}

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页