我正在尝试将 spring oauth2(基于 Java 的配置而不是引导)与 angular 6 集成,
我的 WebSecurityConfigurerAdapter.java 文件是:
package com.novowash.authentication;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.approval.TokenApprovalStore;
import org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler;
import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
NovoAuthenticationProvider novoAuthenticationProvider;
@Autowired
UserDetailsServiceImpl userDetailsServiceImpl;
@Autowired
private PasswordEncoder userPasswordEncoder;
@Autowired
@Qualifier("dataSource")
DataSource dataSource;
@Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
/*auth.inMemoryAuthentication()
.withUser("bill").password("abc123").roles("ADMIN").and()
.withUser("bob").password("abc123").roles("USER");*/
auth.authenticationProvider(novoAuthenticationProvider);
// auth.userDetailsService(userDetailsServiceImpl).passwordEncoder(userPasswordEncoder);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().and()
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS,"/oauth/token").permitAll()
.antMatchers("/signup").permitAll()
.anyRequest().authenticated()
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
@Bean
@Autowired
public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore){
TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
handler.setTokenStore(tokenStore);
handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
handler.setClientDetailsService(clientDetailsService);
return handler;
}
@Bean
@Autowired
public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore);
return store;
}
}
Run Code Online (Sandbox Code Playgroud)
我的身份验证提供程序是:
package com.novowash.authentication;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import com.novowash.Enums.CommonEnums;
import com.novowash.model.User;
import com.novowash.service.UserService;
/**
* @author manish
*
* This Class is responsible for authentication and
* access control of users to cube root Admin module over http in extension of AuthenticationProvider interface of Spring web framework .
*
*/
@Component("novoAuthenticationProvider")
public class NovoAuthenticationProvider implements AuthenticationProvider {
private static final Logger logger = Logger.getLogger(NovoAuthenticationProvider.class);
@Autowired UserService userService;
/* (non-Javadoc)
* @see org.springframework.security.authentication.AuthenticationProvider#authenticate(org.springframework.security.core.Authentication)
*/
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
try {
logger.debug( "ImageVideoAuthenticationProvider.authenticate() authentication.getPrincipal(): " + authentication.getPrincipal());
logger.debug( "ImageVideoAuthenticationProvider.authenticate() authentication.getCredentials(): " + authentication.getCredentials());
String userName = authentication.getPrincipal().toString();
String password = authentication.getCredentials().toString();
User user = userService.findUserByMobile(userName);
if (user == null) {
throw new UsernameNotFoundException(String.format(URLEncoder.encode("Invalid Email OR password", "UTF-8"), authentication.getPrincipal()));
}
if (CommonEnums.STATUS.INACTIVE.ID == user.getStatus()) {
throw new UsernameNotFoundException(String.format(URLEncoder.encode("You are not active", "UTF-8"), authentication.getPrincipal()));
}
if (CommonEnums.STATUS.BLOCK.ID == user.getStatus()) {
throw new UsernameNotFoundException(String.format(URLEncoder.encode("You are blocked. Please contact admin", "UTF-8"), authentication.getPrincipal()));
}
List<String> roles=null;
if(user != null){
roles= userService.getUserRoles(user.getId());
}
List<GrantedAuthority> grantList= new ArrayList<GrantedAuthority>();
if(roles!= null) {
for(String role: roles) {
// ROLE_USER, ROLE_ADMIN,..
GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_" + role);
grantList.add(authority);
}
}
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user, password, grantList);
return token;
} catch (Exception e) {
logger.error( "Error in ImageVideoAuthenticationProvider.authenticate()", e);
throw new AuthenticationServiceException(e.getMessage());
}
}
/* (non-Javadoc)
* @see org.springframework.security.authentication.AuthenticationProvider#supports(java.lang.Class)
*/
public boolean supports(Class<?> clazz) {
return clazz.equals(UsernamePasswordAuthenticationToken.class);
}
}
Run Code Online (Sandbox Code Playgroud)
我已经添加了 CORSFilter.java 。
Angular 6 服务:
import { HttpClient, HttpHeaders, HttpParams } from "@angular/common/http";
import { Inject, Injectable } from "@angular/core";
import { OAuthService } from "angular-oauth2-oidc";
import { environment } from "../../environments/environment";
import { Observable } from "rxjs/Observable";
import { map, combineLatest } from 'rxjs/operators';
@Injectable()
export class ROPCService {
private _user: any;
constructor(private httpClient: HttpClient, private oauthService: OAuthService) {}
public async login(username: string, password: string) {
debugger;
const body = new HttpParams()
.set('username', username)
.set('password', password)
.set('grant_type', environment.auth.grantType);
const headers = new HttpHeaders()
.set("Content-type", "application/x-www-form-urlencoded; charset=utf-8")
.set("Authorization", "Basic d2ViOnNlY3JldA==");
this.httpClient
.post(this.oauthService.tokenEndpoint, body.toString(), {headers:headers})
.pipe(map((res: any) => {
debugger;
})).subscribe(
data => {
debugger;
},
err => {
debugger;
}
)
}
public logOut() {
if (this.oauthService.getRefreshToken() === null) {
return;
}
const refreshToken = this.oauthService.getRefreshToken();
const accessToken = this.oauthService.getAccessToken();
this.oauthService.logOut(true);
const body = new HttpParams().set("client_id", this.oauthService.clientId).set("refresh_token", refreshToken);
return this.httpClient.post(this.oauthService.logoutUrl, body.toString(), {
headers: new HttpHeaders().set("Content-Type", "application/x-www-form-urlencoded"),
});
}
public get user() {
return this._user;
}
public set user(user) {
this._user = user;
}
}
Run Code Online (Sandbox Code Playgroud)
当我调用 /oauth/token URL 时出现 401 错误,我的请求是:

我在后端遇到错误:
2018-08-02 11:52:09 DEBUG DefaultListableBeanFactory:251 - 返回单例 bean 'delegatingApplicationListener' 的缓存实例 2018-08-02 11:52:09 DEBUG ExceptionTranslationFilter:174 - 访问被拒绝(用户是匿名的);重定向到身份验证入口点 org.springframework.security.access.AccessDeniedException:访问被拒绝在 org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) 在 org.springframework.security.access.intercept。 AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233) 在 org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124) 在 org.springframework.security.web.access.intercept.FilterSecurityInterceptor。', GET] 2018-08-02 11:52:09 DEBUG AntPathRequestMatcher:137 - 请求 'OPTIONS /oauth/token' 与 'GET /2018-08-02 11:52:09 DEBUG AndRequestMatcher:69 - 不匹配 2018-08-02 11:52:09 DEBUG HttpSessionRequestCache:62 - 请求未保存为配置的 RequestMatcher 不匹配 2018-08-02 11:52 :09 DEBUG ExceptionTranslationFilter:203 - 调用身份验证入口点。2018-08-02 11:52:09 DEBUG DelegatingAuthenticationEntryPoint:78 - 尝试使用 MediaTypeRequestMatcher 进行匹配 [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@781f892e, matchingMediaTypes=[application/atom+xml, application/x-www-表单 urlencoded、应用程序/json、应用程序/八位字节流、应用程序/xml、多部分/表单数据、文本/xml]、useEquals=false、忽略MediaTypes=[ /]] 2018-08-02 11:52:09 DEBUG MediaTypeRequestMatcher:185 - httpRequestMediaTypes=[] 2018-08-02 11:52:09 DEBUG MediaTypeRequestMatcher:213 - 没有匹配任何媒体类型 2018-018-022 :09 DEBUG DelegatingAuthenticationEntryPoint:78 - 尝试使用 AndRequestMatcher 进行匹配 [requestMatchers=[NegatedRequestMatcher [requestMatcher=MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@781f892e, matchingMediaTypes=[textMedia/htmls], use hiddenType=[text/htmls] []]], MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@781f892e, matchingMediaTypes=[application/atom+xml, application/x-www-form-urlencoded, application/json, application/octet-stream,应用程序/xml,多部分/表单数据,text/xml], useEquals=false, 忽略MediaTypes=[/]]]] 2018-08-02 11:52:09 DEBUG AndRequestMatcher:66 - 尝试使用 NegatedRequestMatcher 进行匹配 [requestMatcher=MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@781f892e,matchingTextMediaTypes] , useEquals=false, ignoreMediaTypes=[]]] 2018-08-02 11:52:09 DEBUG MediaTypeRequestMatcher:185 - httpRequestMediaTypes=[] 2018-08-02 11:52:09 DEBUG MediaTypeRequestMatcher:213 - 没有匹配类型 2018-08-02 11:52:09 DEBUG NegatedRequestMatcher:51 - 匹配 = true 2018-08-02 11:52:09 DEBUG AndRequestMatcher:66 - 尝试使用 MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.ac.ac. ContentNegotiationManager@781f892e, matchingMediaTypes=[application/atom+xml, application/x-www-form-urlencoded,application/json、application/octet-stream、application/xml、multipart/form-data、text/xml]、useEquals=false、忽略MediaTypes=[/ ]] 2018-08-02 11:52:09 DEBUG MediaTypeRequestMatcher:185 - httpRequestMediaTypes=[] 2018-08-02 11:52:09 DEBUG MediaTypeRequestMatcher:213 - 没有匹配任何媒体类型 2018-018-02 52:09 DEBUG AndRequestMatcher:69 - 不匹配 2018-08-02 11:52:09 DEBUG DelegatingAuthenticationEntryPoint:91 - 未找到匹配项。使用默认入口点 org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint@5a1a107f 2018-08-02 11:52:09 DEBUG HstsHeaderWriter:130 - 不注入 HSTS 标头,因为它与 requestMatcher org.springframework.security 不匹配.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@5b4e497d 2018-08-02 11:52:09 DEBUG SecurityContextPersistenceFilter:119 - SecurityContextHolder 现在被清除,因为请求处理完成
这正是您突出显示的错误所说的。您发送的请求方法是 GET,但需要 OPTIONS 方法。
它配置在OAuth2SecurityConfig:
.antMatchers(HttpMethod.OPTIONS,"/oauth/token").permitAll()
Run Code Online (Sandbox Code Playgroud)
将其更改为 GET 应该可以工作。
.antMatchers(HttpMethod.GET,"/oauth/token").permitAll()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
18392 次 |
| 最近记录: |