Java 如何使Spring安全性接受JSON而不是表单参数?
我试图更改JHipster,使其使用JSON对象进行身份验证,而不是表单参数。我已经设法使它的JWT身份验证机制起作用。现在,我想为其他身份验证选项执行此操作 有没有一种简单的方法来更改Spring Security的默认安全配置以允许这样做?以下是JHipster现在使用的内容:Java 如何使Spring安全性接受JSON而不是表单参数?,java,spring-boot,spring-security,jhipster,Java,Spring Boot,Spring Security,Jhipster,我试图更改JHipster,使其使用JSON对象进行身份验证,而不是表单参数。我已经设法使它的JWT身份验证机制起作用。现在,我想为其他身份验证选项执行此操作 有没有一种简单的方法来更改Spring Security的默认安全配置以允许这样做?以下是JHipster现在使用的内容: .and() .rememberMe() .rememberMeServices(rememberMeServices) .rememberMeParameter("remember-me")
.and()
.rememberMe()
.rememberMeServices(rememberMeServices)
.rememberMeParameter("remember-me")
.key(env.getProperty("jhipster.security.rememberme.key"))
.and()
.formLogin()
.loginProcessingUrl("/api/authentication")
.successHandler(ajaxAuthenticationSuccessHandler)
.failureHandler(ajaxAuthenticationFailureHandler)
.usernameParameter("j_username")
.passwordParameter("j_password")
.permitAll()
我希望将以下内容作为JSON而不是表单参数发送:
{username: "admin", password: "admin", rememberMe: true}
我做过这样的事。解决方案并不难,但我做到了创建一个主要基于UserNamePasswordAuthenticationFilter的自定义安全过滤器的技巧 实际上,您应该重写attemptAuthentication方法。仅仅覆盖ActainPassword和ActainUserName可能不会被启用,因为您想要读取请求正文,并且必须同时为这两个参数执行此操作(如果您不创建一种多读HttpServletRequest包装器) 解决方案必须如下所示:
public class JsonUserNameAuthenticationFilter extends UsernamePasswordAuthenticationFilter{
//[...]
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
UsernamePasswordAuthenticationToken authRequest =
this.getUserNamePasswordAuthenticationToken(request);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
//[...]
protected UserNamePasswordAuthenticationToken(HttpServletRequest request){
// here read the request body and retrieve the params to create a UserNamePasswordAuthenticationToken. You may use jackson of whatever you like most
}
//[...]
}
然后您必须配置它。对于这种复杂的配置,我总是使用基于xml的配置
<beans:bean id="jsonUserNamePasswordAuthenticationFilter"
class="xxx.yyy.JsonUserNamePasswordAuthenticationFilter">
<beans:property name="authenticationFailureHandler>
<beans:bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<!-- set the failure url to a controller request mapping returning failure response body.
it must be NOT secured -->
</beans:bean>
</beans:property>
<beans:property name="authenticationManager" ref="mainAuthenticationManager" />
<beans:property name="authenticationSuccessHandler" >
<beans:bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<!-- set the success url to a controller request mapping returning success response body.
it must be secured -->
</beans:bean>
</beans:property>
</beans:bean>
<security:authentication-manager id="mainAuthenticationManager">
<security:authentication-provider ref="yourProvider" />
</security:authentication-manager>
<security:http pattern="/login-error" security="none"/>
<security:http pattern="/logout" security="none"/>
<security:http pattern="/secured-pattern/**" auto-config='false' use-expressions="false"
authentication-manager-ref="mainAuthenticationManager"
create-session="never" entry-point-ref="serviceAccessDeniedHandler">
<security:intercept-url pattern="/secured-pattern/**" access="ROLE_REQUIRED" />
<security:custom-filter ref="jsonUserNamePasswordAuthenticationFilter"
position="FORM_LOGIN_FILTER" />
<security:access-denied-handler ref="serviceAccessDeniedHandler"/>
<security:csrf disabled="true"/>
</security:http>
我只是需要一些非常相似的东西,所以我写了它
这使用了SpringSecurity4.2,WebSecurity配置适配器。在那里,我没有使用…formLogin()…
,而是编写了一个自己的配置程序,在可用时使用JSON,如果不可用则默认为Form(因为我需要这两种功能)
我从org.springframework.security.config.annotation.web.configurers.formloginconfiguler
和org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
中复制了所有需要呈现的内容(但我并不在意)
很可能您还需要复制其他函数,但原则上应该这样做
最后是实际解析JSON的过滤器。代码示例是一个类,因此可以直接复制
/**WebSecurityConfig,允许使用JSON Post请求进行身份验证*/
@配置
@EnableWebSecurity(调试=false)
公共类WebSecurityConfig扩展了WebSecurityConfigureAdapter{
//资源在这里
@凌驾
受保护的无效配置(HttpSecurity http)引发异常{
//在这里,您需要配置路径、身份验证提供程序等。
//最初这是http.formLogin().loginPage。。。
http.apply(新的JSonLoginConfiguler()
.loginPage(“/authenticate”)
.successHandler(新的SimpleLauthenticationSuccessHandler(“/dashboard”))
.permitAll());
}
/**这是强制JSONAuthenticationFilter的配置程序。
*基于org.springframework.security.config.annotation.web.configurers.FormLoginConfiguler
*/
私有类JSONLoginConfiguler扩展
AbstractAuthenticationFilterConfigure{
公共JSONLoginConfiguler(){
super(新的JSONAuthenticationFilter(),null);
}
@凌驾
公共JSONLoginConfiguration登录页面(字符串登录页面){
返回super.loginPage(loginPage);
}
@凌驾
受保护的请求匹配器createLoginProcessingUrlMatcher(字符串loginProcessingUrl){
返回新的AntPathRequestMatcher(loginProcessingUrl,“POST”);
}
}
/**这是实际处理json的过滤器
*/
私有类JSONAuthenticationFilter扩展了UsernamePasswordAuthenticationFilter{
受保护字符串获取密码(JsonObject obj){
返回obj.getString(getPasswordParameter());
}
受保护字符串获取用户名(JsonObject obj){
返回obj.getString(getUsernameParameter());
}
@凌驾
公共身份验证尝试身份验证(HttpServletRequest请求、HttpServletResponse响应)
抛出AuthenticationException{
if(!“application/json”.equals(request.getContentType())){
//请注意,UsernamePasswordAuthenticationFilter中的objtainPassword和Username
//具有不同的方法签名
返回super.attemptAuthentication(请求、响应);
}
try(BufferedReader=request.getReader()){
//使用javax.json.json进行json转换
JsonObject obj=Json.createReader(reader.readObject();
字符串用户名=获取用户名(obj);
字符串密码=获取密码(obj);
UsernamePasswordAuthenticationTokenAuthRequest=新UsernamePasswordAuthenticationToken(
用户名、密码);
返回此.getAuthenticationManager().Authentication(authRequest);
}捕获(IOEX异常){
抛出新的AuthenticationServiceException(“解析请求失败”,ex);
}
}
}
}
你能看看这篇文章吗:XML配置完全崩溃了。请参阅。@您确定吗?这个回复已经有一段时间了,但它是从一个测试和工作的例子。到底什么东西坏了?当然,有些元素没有配置,只是放在xml注释标记的地方,但在我编写我的answer@jlumietu是的,非常肯定<第10行的代码>
没有结束标记,第1行的代码>没有结束标记。要正确,您必须将第15行的
替换为
@Younes您是否已使用设置填补了注释中的空白?等等,我发现了一个输入错误…我从loginPage方法启动时收到一个异常,它太长,无法作为注释发布,原因是:java.lang.IllegalStateException:securityBuilder不能在org.springframework.security.config.annotation.SecurityConfigureAdapter.getBuilder(SecurityC