嗨,我正在尝试使用Spring安全性来实现OAuth2,到目前为止,我已经设法使用grant_type=password
来实现它,我得到了token, time, refresh token
并且资源得到了预期的保护。
现在,我的下一步是使用authorization_code+pkce
实现。
当我用我的身份验证服务器详细信息替换所有客户端凭据时,我一直遵循此tutorial,收到http://localhost:8080/oauth/login
Not Found
消息。请求的内容类似于http://localhost:8080/auth/oauth/authorize?client_id=SampleClientId&redirect_uri=http://localhost:8083/ui2/login&response_type=code&state=5ppnu6
我的配置和服务器文件如下,这是我第一次在服务器端实现oauth,所以我可能做的很废话,请帮助我纠正一下。
AuthorizationServerConfig.java
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
@Autowired
private AuthenticationManager manager;
@Autowired
private BCryptPasswordEncoder passwordEncoder;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("SampleClientId")
.secret(passwordEncoder.encode("secret"))
.authorizedGrantTypes("password", "authorization_code", "implicit", "refresh_token")
.scopes(UserDetailsServiceImpl.Role.USER.name(),
UserDetailsServiceImpl.Role.MODERATOR.name(),
UserDetailsServiceImpl.Role.ADMIN.name())
.redirectUris("http://localhost:8080/callback", "http://localhost:8083/ui2/login")
.accessTokenValiditySeconds(3600)
.refreshTokenValiditySeconds(4800);
}
@Override
public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore)
.authenticationManager(manager);
}
}
BeansConfig.java
@Configuration
public class BeansConfig {
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public UserDetailsServiceImpl userDetailsService() {
return new UserDetailsServiceImpl();
}
}
ResourceServerConfig.java
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "resource_id";
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(RESOURCE_ID).stateless(false);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.anonymous().disable()
.authorizeRequests()
.antMatchers("/users/**").authenticated()
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
SecurityConfig.java
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Resource(name = "userDetailsService")
private UserDetailsServiceImpl userDetailsService;
@Autowired
private BCryptPasswordEncoder passwordEncoder;
public SecurityConfig() {
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
userDetailsService.init(passwordEncoder);
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/login", "/oauth/authorize")
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.permitAll();
}
}
UsersControllers.java
@RestController
public class UsersControllers {
@RequestMapping(value = "/users", method = RequestMethod.GET)
ResponseEntity<Map<String, String>> get() {
final Map<String, String> map = new HashMap<>();
map.put("status", "ok");
return ResponseEntity.ok(map);
}
@GetMapping(value = "/user/me")
Principal me(Principal principal) {
final Map<String, String> map = new HashMap<>();
map.put("status", "ok");
return principal;
}
}
UserDetailsImpl.java
public class UserDetailsImpl implements UserDetails {
private final String username;
private final String password;
private final List<GrantedAuthority> roles;
public UserDetailsImpl(String username, String password, List<GrantedAuthority> roles) {
this.username = username;
this.password = password;
this.roles = roles;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return roles;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return this.username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
UserDetailsServiceImpl.java
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
private static final Logger LOGGER = Logger.getLogger(UserDetailsServiceImpl.class.getSimpleName());
public enum Role {
USER,
MODERATOR,
ADMIN
}
private final List<UserDetailsImpl> users = new ArrayList<>();
public UserDetailsServiceImpl() {
}
public void init(BCryptPasswordEncoder passwordEncoder) {
users.add(new UserDetailsImpl("john", passwordEncoder.encode("doe"), buildUserAuthorities()));
users.add(new UserDetailsImpl("wow", passwordEncoder.encode("baby"), buildModeratorAuthorities()));
}
private List<GrantedAuthority> buildUserAuthorities() {
final List<GrantedAuthority> authorityList = new ArrayList<>();
authorityList.add(new SimpleGrantedAuthority(Role.USER.name()));
return authorityList;
}
private List<GrantedAuthority> buildModeratorAuthorities() {
final List<GrantedAuthority> authorityList = new ArrayList<>();
authorityList.add(new SimpleGrantedAuthority(Role.MODERATOR.name()));
return authorityList;
}
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
for (UserDetailsImpl details : users) {
if (details.getUsername().equals(s)) {
LOGGER.warning("Found user: " + s);
return details;
}
}
throw new UsernameNotFoundException("User " + s + " notfound");
}
public List<UserDetailsImpl> getUsers() {
return users;
}
}
maven文件中的某些内容
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</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-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>