我已经使用Spring安全保护了我的服务器,并尝试测试它。我的测试包括登录测试用户(在DB中已经存在),然后尝试访问一个安全URL,该URL要求用户进行身份验证,并具有特定的角色。
这是我的密码
我创建了一个安全上下文:
<!-- URL's that start with the "app/secured" prefix requires authentication -->
<http auto-config="false" use-expressions="true">
<form-login login-processing-url="/app/login"
authentication-success-handler-ref="ajaxAuthenticationSuccessHandler"
authentication-failure-handler-ref="ajaxAuthenticationFailureHandler" />
<intercept-url pattern="/**" access="permitAll" />
<intercept-url pattern="**/app/secured/**" access="isAuthenticated()" />
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="myUserDetailsService">
<password-encoder ref="passwordEncoder">
<salt-source user-property="creationTime" />
</password-encoder>
</authentication-provider>
</authentication-manager>
<beans:bean id="passwordEncoder"
class="me.co.server.bl.security.ExtendedShaPasswordEncoder" />
<beans:bean id="ajaxAuthenticationSuccessHandler"
class="me.co.server.web.resource.register.login.AjaxAuthenticationSuccessHandler" />
<beans:bean id="ajaxAuthenticationFailureHandler"
class="me.co.server.web.resource.register.login.AjaxAuthenticationFailureHandler" />
<beans:bean id="myUserDetailsService"
class="me.co.server.bl.security.MyUserDetailsService" />我在我的web.xml顶部添加了安全上下文和安全过滤器:
<!-- Spring Security -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/applicationContext.xml
/WEB-INF/spring/security-context.xml
</param-value>
</context-param>以下是我的web层泽西实现:
@Path("/secured/{resourceName}")
@Component
public class SecuredResourceProvider extends ServiceResourceProvider {
/*--- Members ---*/
private ILogger logger = LogManager.getLogger(SecuredResourceProvider.class);
@Inject
protected SecuredResourceFactory securedResourceFactory;
/*--- Constructors ---*/
protected SecuredResourceProvider() {
super("Secured");
}
/*--- Public Methods ---*/
@GET
@Produces("application/json")
@Path("/{resourceId}")
public String getSecuredResource(@PathParam("resourceId") String resourceId, @PathParam("resourceName") String resourceName)
throws UnhandledResourceException, UnauthorizedAccessException, ServerInternalErrorException, JsonException, ResourceArgumentException {
// NOT IMPLEMENTED AT THE MOMENT //
return null;
}
@PUT
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.TEXT_PLAIN)
@Path("/{code}")
public String putSecuredResource(String resourceData, @PathParam("code") String ownerResourceId, @PathParam("resourceName") String resourceName)
throws UnhandledResourceException, UnauthorizedAccessException, ServerInternalErrorException, JsonException, ResourceArgumentException {
if (SecuredResources.isSecuredResource(resourceName)) {
IResource<String> resource = securedResourceFactory.getResourceInstance(resourceName);
String resourceString = resource.put(ownerResourceId, resourceData);
return createReturnResourceString(resourceString);
} else {
throw new UnhandledResourceException("Invoking a secured method for an unsecured resource " + resourceName);
}
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.TEXT_PLAIN)
@Path("/{resourceId}")
public String postSecuredResource(String resourceData, @PathParam("resourceName") String resourceName, @PathParam("resourceId") String resourceId)
throws UnhandledResourceException, UnauthorizedAccessException, ServerInternalErrorException, JsonException, ResourceArgumentException {
if (SecuredResources.isSecuredResource(resourceName)) {
IResource<String> resource = securedResourceFactory.getResourceInstance(resourceName);
String resourceString = resource.post(resourceId, resourceData);
return createReturnResourceString(resourceString);
} else {
throw new UnhandledResourceException("Invoking a secured method for an unsecured resource " + resourceName);
}
}
@DELETE
@Consumes(MediaType.TEXT_PLAIN)
@Produces(MediaType.TEXT_PLAIN)
@Path("/{code}")
public String deleteSecuredResource(String resourceId, @PathParam("code") String ownerResourceId, @PathParam("resourceName") String resourceName)
throws UnhandledResourceException, UnauthorizedAccessException, ServerInternalErrorException, JsonException, ResourceArgumentException {
if (SecuredResources.isSecuredResource(resourceName)) {
IResource<String> resource = securedResourceFactory.getResourceInstance(resourceName);
String resourceString = resource.delete(ownerResourceId, resourceId);
return createReturnResourceString(resourceString);
} else {
throw new UnhandledResourceException("Invoking a secured method for an unsecured resource " + resourceName);
}
}
}这里没有什么特别之处,只是根据我的url的拦截定义,这个spring应该是安全的(需要经过身份验证的用户)。web层将请求委托给业务逻辑层,业务逻辑层使用方法-安全注释进行安全保护:
@Override
@Secured("ROLE_BRAND_MANAGER")
public String post(String gymCode, String trainingSessionJson) throws UnhandledResourceException, ServerInternalErrorException,
ResourceArgumentException, JsonException {
...
}为此,我将全局方法安全声明添加到我的application-context中。
<security:global-method-security secured-annotations="enabled" proxy-target-class="true"/>发布的用户是一个品牌经理(据权威人士所知),但目前没有持久化,而是从实体返回硬编码:
@Entity
@Table(name = "brand_managers")
public class BrandManager implements Serializable, UserDetails {
/** Serial version unique id */
private static final long serialVersionUID = -7992146584570782015L;
public static final String ROLE = "ROLE_BRAND_MANAGER";
/*--- Members ---*/
/** The unique, internal ID of the entity. */
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
/**
* The creation time of this user
*/
@Column(name = "creation_time")
protected long creationTime;
/**
* The hashed password
*/
@Column(name = "password")
protected String password;
@Column(name = "first_name")
protected String firstName;
@Column(name = "last_name")
protected String lastName;
@Column(name = "email")
protected String eMail;
@Column(name = "address1")
protected String address1;
@Column(name = "address2", nullable = true)
protected String address2;
@Column(name = "city")
protected String city;
@Column(name = "state")
protected String state;
@Column(name = "zip", nullable = true)
protected String zip;
@Column(name = "country")
protected String country;
@Column(name = "phone")
protected String phone;
@Column(name = "brand_id")
protected int brandId;
/*--- Constructors ---*/
/**
* default
*/
public BrandManager() {
setCreationTime(Calendar.getInstance().getTimeInMillis());
}
public BrandManager(String password, String firstName, String lastName, String eMail, String address1, String address2, String city,
String state, String zip, String country, String phone, int brandId) {
this();
this.password = password;
this.firstName = firstName;
this.lastName = lastName;
this.eMail = eMail;
this.address1 = address1;
this.address2 = address2;
this.city = city;
this.state = state;
this.zip = zip;
this.country = country;
this.phone = phone;
this.brandId = brandId;
}
/*--- Overridden Methods ---*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
// currently not holding authorities in DB, but returning hard-coded
return AuthorityUtils.createAuthorityList(ROLE);
}
... getter and setters...
}我的UserDetailsService简单地从DB加载用户(使用dao委托)。
现在,当我测试我的服务器(运行在tomcat中)并调用安全URL时,我看到了一些奇怪的东西。我在AffirmativeBased类的“决定”方法中放置了一个断点,这是security的DecisionManager的默认实现:
公共无效判定(身份验证、对象对象、集合configAttributes)抛出AccessDeniedException { int = 0;
for (AccessDecisionVoter voter : getDecisionVoters()) {
int result = voter.vote(authentication, object, configAttributes);
if (logger.isDebugEnabled()) {
logger.debug("Voter: " + voter + ", returned: " + result);
}
switch (result) {
case AccessDecisionVoter.ACCESS_GRANTED:
return;
case AccessDecisionVoter.ACCESS_DENIED:
deny++;
break;
default:
break;
}
}当调用我的服务方法时,它使用@Secured注释进行注释,并且我看到"configAttributes“属性包含一个值为permitAll的元素,这不是我所期望看到的。我希望能看到"ROLE_BRAND_MANAGER“。我调试错地方了吗?我如何知道我的安全相关代码是正确的?
提前谢谢你,瑜伽
发布于 2012-08-06 06:58:33
如php-编码器所建议的:
第一条规则总是占上风,所以我建议重新排序拦截-url-s,并将permitAll移到最后。
我不得不改变我的url截取定义的顺序,现在这个流程是有意义的。
发布于 2012-08-03 23:35:40
实际上,在这样的命名空间配置中有两个AccessDecisionManager实例。一种用于web安全,另一种用于方法安全。如果需要,两者都可以被重写。
您的断点可能意味着您正在看到web安全性之一(如果您在调试器中检查堆栈,这一点应该很明显)。
确保global-method-security与您想要保护的bean位于同一个上下文文件中。Security中有更多信息,您还可以找到关于父/子Spring上下文文件的其他讨论。通常,如果您想保护在dispatcher servlet配置文件(例如spring-servlet.xml)中声明的MVC控制器或其他web bean,那么它也应该在其中。从主应用程序上下文(由ContextLoaderListener在web.xml中加载的应用程序上下文)中看不到它们,因此如果将方法安全性元素放在其中,它将无法工作。
https://stackoverflow.com/questions/11802071
复制相似问题