这个注解支持必须卸载 MVC 的配置文件中,这是因为我们将注解加载 Controller 层上,该层由前端控制器加载,故位于 Spring Ioc 的子容器中,而 MVC 配置文件也是由 DispatcherServlet 加载的。将注解支持写到 Spring 的配置文件中注解将会不生效。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<!--
开启权限控制的注解支持, 开启一个就可以了
secured-annotations="enabled" Spring Security 内部的权限控制注解开关
pre-post-annotations="enabled" Spring 指定的权限控制的注解开关
jsr250-annotations="enabled" 开启 java-250 注解支持
-->
<security:global-method-security
secured-annotations="enabled"
pre-post-annotations="enabled"
jsr250-annotations="enabled"/>
</beans>
/**
* Created with IntelliJ IDEA.
*
* @author Demo_Null
* @date 2020/10/12
* @description Spring Security 内部制定的注解
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Secured({"ROLE_USER","ROLE_ADMIN"})
@RequestMapping("/findAll")
public Object findAll(){
return obj;
}
}
/**
* Created with IntelliJ IDEA.
*
* @author Demo_Null
* @date 2020/10/12
* @description jsr-250 注解
*/
@RestController
@RequestMapping("/user")
public class UserController {
@RolesAllowed({"ROLE_USER","ROLE_ADMIN"})
@RequestMapping("/findAll")
public Object findAll(){
return obj;
}
}
此注解需要使用 SPEL 表达式,所以想要使用该注解需要在 Security 配置文件中开启 SPEL 表达式支持,Security 默认 use-expressions="true"
,开启之后配置文件中的角色信息应该使用 <security:intercept-url pattern="/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')"/>
或者 access=“hasRole(‘ROLE_USER’,‘ROLE_ADMIN’)”,二者之间的区别是 hasAnyRole 只需要拥有二者之间任意权限即可,而 hasRole 需要同时具有有所权限才行。还有另外两种表示 hasAnyAuthority、hasAuthority 与之前那种配置的区别是前者没有 ROLE_
将会自动添加,后者不会。
/**
* Created with IntelliJ IDEA.
*
* @author Demo_Null
* @date 2020/10/12
* @description Spring 的 el 表达式注解
*/
@RestController
@RequestMapping("/user")
public class UserController {
@PreAuthorize("hasAnyAuthority('ROLE_USER','ROLE_ADMIN')")
@RequestMapping("/findAll")
public Object findAll(){
return obj;
}
}
<security:http auto-config="true" use-expressions="true">
<!-- 省略其他配置 -->
<!-- 处理 403 异常 -->
<security:access-denied-handler error-page="/403.html"/>
</security:http>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!--处理403异常-->
<error-page>
<error-code>403</error-code>
<location>/403.html</location>
</error-page>
<!--处理404异常-->
<error-page>
<error-code>404</error-code>
<location>/404.html</location>
</error-page>
</web-app>
@Component
public class HandlerControllerException implements HandlerExceptionResolver {
/**
* @param httpServletRequest
* @param httpServletResponse
* @param o 出现异常的对象
* @param e 出现的异常信息
* @return ModelAndView
*/
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, Object o, Exception e) {
ModelAndView mv = new ModelAndView();
// 将异常信息放入 request 域中,基本不用
mv.addObject("errorMsg", e.getMessage());
// 指定不同异常跳转的页面
if(e instanceof AccessDeniedException){
mv.setViewName("redirect:/403.html");
}else {
mv.setViewName("redirect:/500.html");
}
return mv;
}
}
可以利用 AOP 做全局异常处理
@ControllerAdvice
public class HandlerControllerAdvice {
@ExceptionHandler(AccessDeniedException.class)
public String handlerException(){
return "redirect:/403.html";
}
@ExceptionHandler(RuntimeException.class)
public String runtimeHandlerException(){
return "redirect:/500.html";
}
}