欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

3 Spring Security详解(授权及保护视图)

程序员文章站 2024-02-15 12:04:59
...

不同用户登录后看到的菜单是不一样的。例如,管理员能够看到系统管理,而普通用户看不到。

实现这一功能需要两步:

  • 给用户不同的权限。
  • Spring Security使用JSP标签库来渲染视图。

1 保护视图

1.1 Spring SecurityJSP标签库

Spring Security的JSP标签库很小,只包含三个标签:

3 Spring Security详解(授权及保护视图)

为了使用JSP标签库,我们需要在对应的JSP中声明它:

<%@taglib uri="http://www.springframework.org/security/tags" prefix="security" %>

 只要标签库在JSP文件中进行了声明,我们就可以使用它了。让我们看看Spring Security提供的这三个标签是如何工作的。

1.1.1 访问认证信息的细节<security:authentication>

借助Spring Security JSP标签库,所能做到的最简单的一件事情就是便利地访问用户的认证信息。例如,对于Web站点来讲,在页面顶部以用户名标示显示“欢迎”或“您好”信息是很常见的。这恰恰是<security:authentication>能为我们所做的事情。例如:

3 Spring Security详解(授权及保护视图)

其中,property用来标示用户认证对象的一个属性。可用的属性取决于用户认证的方式。但是,我们可以依赖几个通用的属性,在不同的认证方式下,它们都是可用的。

3 Spring Security详解(授权及保护视图)

在我们的示例中,实际上渲染的是principal属性中嵌套的username属性。

1.1.2 访问认证信息的细节<security:authorize>

有时候视图上的一部分内容需要根据用户被授予了什么权限来确定是否渲染。对于已经登录   的用户显示登录表单,或者对还未登录的用户显示个性化的问候信息都是毫无意义的。

Spring Security的<security:authorize>JSP标签能够根据用户被授予的权限有条件地渲染页面的部分内容。

用<security:authorize>标签来为具有ROLE_ORDER和ROLE_ADMIN角色的用户显示订单管理。

 <security:authorize access="hasAnyRole('ROLE_ORDER', 'ROLE_ADMIN')">
          <i class="fa fa-circle-o"></i> 订单管理</a></li>
 </security:authorize>

access属性被赋值为一个SpEL表达式,这个表达式的值将确定<security: authorize>标签主体内的内容是否渲染。这里我们使用了hasRole('ROLE_SPITTER')  表达式来确保用户具有ROLE_SPITTER角色。但是,当你设置access属性时,可以任意发   挥SpEL的强大威力。

但是我构造的这个示例还有一件事让人很困惑。尽管我想限制管理功能只能给habuma用户, 但使用JSP标签表达式并不见得理想。确实,它能在视图上阻止链接的渲染。但是没有什么可以阻止别人在浏览器的地址栏手动输入“/admin”这个URL。

 这是<security:authorize>的url属性所要做的事情。它不像access属性那样明确声明安全性限制,url属性对一个给定的URL模式会间接引用其安全性约束。鉴于我们已经在Spring Security配置中为“/admin”声明了安全性约束,所以我们可以这样使用url属性:

3 Spring Security详解(授权及保护视图)

 因为只有基本信息中用户名为“habuma”的已认证用户才能访问“/admin” URL,所以只有满足以上条件,<security:authorize>标签主体中的内容才会被渲染。

2 授权操作

2.1 动态展示菜单

在aside.jsp对每个菜单通过SpringSecurity标签库指定访问所需角色。

<security:authorize access="hasAnyRole('ROLE_PRODUCT', 'ROLE_ADMIN')">
   <li id="system-setting"><a href="${pageContext.request.contextPath}/product/findAll">
      <i class="fa fa-circle-o"></i> 产品管理 </a></li>
</security:authorize>
<security:authorize access="hasAnyRole('ROLE_ORDER', 'ROLE_ADMIN')">
   <li id="system-setting"><a href="${pageContext.request.contextPath}/order/findAll">
      <i class="fa fa-circle-o"></i> 订单管理</a></li>
</security:authorize>

我们做个测试,xiaoming这个用户现在有普通用户角色ROLE_USER和ROLE_PRODUCT,用xiaoming登录后,果然只看到了订单管理:

3 Spring Security详解(授权及保护视图)

那么问题来了,是不是现在已经授权成功了呢?答案是否定的!你可以试试直接去访问订单的http请求地址:

3 Spring Security详解(授权及保护视图)

我们发现xiaoming其实是可以操作订单模块的,只是没有把订单功能展示给xiaoming而已!
总结一句:页面动态菜单的展示只是为了用户体验,并未真正控制权限!

2.2 真正的授权

说明:SpringSecurity可以通过注解的方式来控制类或者方法的访问权限。注解需要对应的注解支持,若注解放在
controller类中,对应注解支持应该放在mvc配置文件中,因为controller类是有mvc配置文件扫描并创建的,同
理,注解放在service类中,对应注解支持应该放在spring配置文件中。
由于我们现在是模拟业务操作,并没有
service业务代码,所以就把注解放在controller类中了。

2.2.1 开启授权的注解支持

这里给大家演示三类注解,但实际开发中,用一类即可!

 <!--
        开启权限控制的注解支持
        secured-annotations="enabled"     springSecurity内部的权限控制注解开关
        pre-post-annotations="enabled"     spring指定的权限控制的注解开关
        jsr250-annotations="enabled"      开启java250注解支持
        -->
    <security:global-method-security
            secured-annotations="enabled"
            pre-post-annotations="enabled"
            jsr250-annotations="enabled"/>

2.2.2 在注解支持对应类或者方法上添加注解

@Controller
@RequestMapping("/order")
public class OrderController {
    @RequestMapping("/findAll")
    @PreAuthorize("hasAnyAuthority('ROLE_ORDER','ROLE_ADMIN')")//spring的el表达式注解
    public String findAll(){
        return "order-list";
    }
}

权限不足,403错误

3 Spring Security详解(授权及保护视图)

3 权限不足异常处理 

大家也发现了,每次权限不足都出现403页面,着实难堪!体会一下:

3 Spring Security详解(授权及保护视图)

现在我们立马消灭它!

方式一: 在spring-security.xml配置文件中处理

<security:http auto-config="true" use-expressions="true">
  <security:access-denied-handler error-page="/403.jsp"/>
</security:http>

3 Spring Security详解(授权及保护视图)

方式二:在web.xml中处理 

<error-page>
    <error-code>403</error-code>
    <location>/403.jsp</location>
</error-page>

方式三:编写异常处理器

@ControllerAdvice
public class HandlerControllerAdvice{

    @ExceptionHandler(AccessDeniedException.class)
    public String handlerException(){
        return "redirect:/403.jsp";
    }

    @ExceptionHandler(RuntimeException.class)
    public String runtimeHandlerException(){
        return "redirect:/500.jsp";
    }

}

 

相关标签: Spring实战