Spring MVC Controller的方法搭配Spring Security的@PreAuthorize
控管存取權限設定如下。
首先在Spring的設定檔applicationContext.xml
加入<global-method-security>
。
<security:global-method-security pre-post-annotations="enabled"/>
要注意的是,上面的設定必須與下面Spring MVC用來掃描@Controller
的標籤放在同個context,也就是同一個配置檔中@PreAuthorize
才會發生作用,例如下面統一放在Spring的配置檔applicationContext.xml
。
如果分別放在不同的context,例如<global-method-security>
放在ApplicationContext
(例如applicationContext.xml
),而<mvc:annotation-driven />
及<context:component-scan />
放在DispatcherServlet
的WebApplicationContext
(例如dispatcher-servlet.xml
)則@PreAuthorize
無法作用。
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<security:global-method-security pre-post-annotations="enabled"/>
<mvc:annotation-driven />
<context:component-scan base-package="idv.matt.controller, idv.matt.controller.api"/>
<!-- Spring Security REST-->
<security:http entry-point-ref="restAuthenticationEntryPoint">
<security:intercept-url pattern="/api/**" access="hasRole('ROLE_ADMIN')"/>
<security:form-login/>
<security:logout/>
</security:http>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider>
<security:user-service>
<security:user name="matt" password="matt" authorities="ROLE_ADMIN, ROLE_USER"/>
<security:user name="john" password="john" authorities="ROLE_USER"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
<beans:bean id="restAuthenticationEntryPoint" class="idv.matt.security.RestAuthenticationEntryPoint"/>
</beans:beans>
當然除上之外Spring Security的其他設定包括要驗證的url pattern等記得要設定好。
下面是要被存取的MyAPIController.hello()
,在方法前加上@PreAuthorize("hasRole('ROLE_ADMIN')")
,則此方法只有具有'ROLE_ADMIN'
身分的使用者可以存取。
MyAPIController.java
package idv.matt.controller.api;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value="/api")
public class MyAPIController {
@GetMapping(value="/hello")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public String hello() {
System.out.println("MyAPIController.hello()");
Object principal = SecurityContextHolder.getContext()
.getAuthentication()
.getPrincipal();
System.out.println(principal.toString());
return "hello";
}
}
RestAuthenticationEntryPoint.java
package idv.matt.security;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint{
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException arg2) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
根據以上設定,目前有兩個使用者matt和john。
matt因為有'ROLE_ADMIN'
權限,所以登入後可以通過權限驗證存取該方法,反之john只有'ROLE_USER'
權限所以存取時會回傳HTTP Status 403 - Access is denied
。
設定好後在瀏覽器網址列輸入http://localhost:8080/<APP_NAME>/login
進入登入畫面,輸入帳號密碼登入後在瀏覽器網址列輸入http://localhost:8080/<APP_NAME>/api/hello
來存取MyAPIController.hello()
。登入者若是matt可以正常存取,若是john就會返回HTTP Status 403 - Access is denied
。
除了在xml
配置檔的設定方是外,也可在Java程式中以@EnableGlobalMethodSecurity
的方式設定。
參考:
沒有留言:
張貼留言