【发布时间】:2017-01-01 20:13:58
【问题描述】:
我正在尝试使用 Spring Security 来保护我的 Rest API。 所以我的要求是用户应该通过 api 调用在标头中传递一个 apiKey,它将得到验证 w.r.t 到预定义的凭据。
假设我有 apikey:'ABCdEfG' 角色:'ROLE_ADMIN'
所以我编写了安全过滤器和身份验证提供程序的自定义实现。 apiKey 的身份验证工作正常,但它不是验证特定 api 所需的角色。
即如果没有 apiKey,我无法访问我的 api,但它无法验证所需的角色。
我当前的实现如下:
如果我在某处做错了,请告诉我。
应用上下文:
<security:global-method-security
pre-post-annotations="enabled" />
<security:http entry-point-ref="authenticationEntryPoint"
create-session="stateless">
<security:intercept-url pattern="/api/*"
access="ROLE_ADMIN" />
<security:custom-filter before="FORM_LOGIN_FILTER"
ref="restAuthenticationFilter" />
</security:http>
<bean id="restAuthenticationFilter"
class="com.myapp.authentication.RestAuthenticationFilter2">
<property name="authenticationManager" ref="authenticationManager" />
<property name="authenticationSuccessHandler" ref="authenticationSuccessHandler" />
</bean>
<bean class="com.myapp.authentication.RestAuthenticationEntryPoint"
id="authenticationEntryPoint"></bean>
<bean
class="com.myapp.authentication.RestAuthenticationSuccessHandler"
id="authenticationSuccessHandler"></bean>
<bean class="com.myapp.authentication.CustomAuthenticationProvider"
id="customAuthenticationProvider"></bean>
<bean class="com.myapp.authentication.util.UserAuthenticationDAO"
factory-method="getInstance" id="userAuthenticationDAO"></bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider
ref="customAuthenticationProvider" />
</security:authentication-manager>
角色.java
import org.springframework.security.core.GrantedAuthority;
@SuppressWarnings("serial")
public class Role implements GrantedAuthority {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthority() {
return this.name;
}
}
用户.java
import java.util.List;
import org.springframework.security.core.userdetails.UserDetails;
@SuppressWarnings("serial")
public class User implements UserDetails {
private String apiKey;
/* Spring Security related fields */
private List<Role> authorities;
private boolean accountNonExpired = true;
private boolean accountNonLocked = true;
private boolean credentialsNonExpired = true;
private boolean enabled = true;
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public List<Role> getAuthorities() {
return authorities;
}
public void setAuthorities(List<Role> authorities) {
this.authorities = authorities;
}
public boolean isAccountNonExpired() {
return accountNonExpired;
}
public void setAccountNonExpired(boolean accountNonExpired) {
this.accountNonExpired = accountNonExpired;
}
public boolean isAccountNonLocked() {
return accountNonLocked;
}
public void setAccountNonLocked(boolean accountNonLocked) {
this.accountNonLocked = accountNonLocked;
}
public boolean isCredentialsNonExpired() {
return credentialsNonExpired;
}
public void setCredentialsNonExpired(boolean credentialsNonExpired) {
this.credentialsNonExpired = credentialsNonExpired;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
@Override
public String getPassword() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getUsername() {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean equals(Object obj) {
return this.apiKey.equals(((User) obj).getApiKey());
}
}
CustomAuthentiCationToken.java
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
public class CustomAuthenticationToken extends UsernamePasswordAuthenticationToken {
/**
*
*/
private static final long serialVersionUID = 1L;
private String token;
public CustomAuthenticationToken(String token) {
super(null, null);
this.token = token;
}
public String getToken() {
return token;
}
@Override
public Object getCredentials() {
return null;
}
@Override
public Object getPrincipal() {
return null;
} }
身份验证过滤器
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import com.myapp.authentication.bean.CustomAuthenticationToken;
public class RestAuthenticationFilter2 extends AbstractAuthenticationProcessingFilter {
protected RestAuthenticationFilter2() {
super("/**");
}
@Override
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
return true;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
String header = request.getHeader("Authorization");
if (header == null) {
throw new BadCredentialsException("No token found in request headers");
}
//String authToken = header.substring(7);
String authToken = header.trim();
CustomAuthenticationToken authRequest = new CustomAuthenticationToken(authToken);
return getAuthenticationManager().authenticate(authRequest);
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
FilterChain chain, Authentication authResult) throws IOException, ServletException {
super.successfulAuthentication(request, response, chain, authResult);
// As this authentication is in HTTP header, after success we need to
// continue the request normally
// and return the response as if the resource was not secured at all
chain.doFilter(request, response);
}
}
身份验证提供者
public class CustomAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
@Autowired
RetinaAuthenticationService retinaAuthenticationService;
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
// TODO Auto-generated method stub
}
@Override
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
CustomAuthenticationToken customAuthenticationToken = (CustomAuthenticationToken) authentication;
String token = customAuthenticationToken.getToken();
User user = retinaAuthenticationService.loadUserByApiKey(token);
if (null != user) {
return user;
} else {
throw new BadCredentialsException("API token is not valid");
}
}
}
【问题讨论】:
-
对不起,我真的不明白是哪个问题。 apikey 得到验证,然后,会发生什么,请求的角色没有被授予?
-
apiKey 在没有检查角色的情况下得到验证。无论我在intercept-url 中定义什么角色,它仍然适用于apiKey。
-
你请求的网址怎么样?
-
我正在通过 Post 客户端请求 URL,我在其中为 apiKey 添加了额外的标头参数。
-
我的意思是你要什么网址。
标签: java spring spring-security