第 17 章 匿名登录

匿名登录,即用户尚未登录系统,系统会为所有未登录的用户分配一个匿名用户,这个用户也拥有自己的权限,不过他是不能访问任何被保护资源的。

设置一个匿名用户的好处是,我们在进行权限判断时,可以保证SecurityContext中永远是存在着一个权限主体的,启用了匿名登录功能之后,我们所需要做的工作就是从SecurityContext中取出权限主体,然后对其拥有的权限进行校验,不需要每次去检验这个权限主体是否为空了。这样做的好处是我们永远认为请求的主体是拥有权限的,即便他没有登录,系统也会自动为他赋予未登录系统角色的权限,这样后面所有的安全组件都只需要在当前权限主体上进行处理,不用一次一次的判断当前权限主体是否存在。这就更容易保证系统中操作的一致性。

17.1. 配置文件

在配置文件中使用auto-config="true"就会启用匿名登录功能。在启用匿名登录之后,如果我们希望允许未登录就可以访问一些资源,可以在进行如下配置。

<http auto-config='true'>
    <intercept-url pattern="/" access="IS_AUTHENTICATED_ANONYMOUSLY" />
    <intercept-url pattern="/admin.jsp" access="ROLE_ADMIN" />
    <intercept-url pattern="/**" access="ROLE_USER" />
</http>
        

在access中指定IS_AUTHENTICATED_ANONYMOUSLY后,系统就知道此资源可以被匿名用户访问了。当未登录时访问系统的“/”,就会被自动赋以匿名用户的身份。我们可以使用taglib获得用户的权限主体信息。

这里的IS_AUTHENTICATED_ANONYMOUSLY将会交由AuthenticatedVoter处理,内部会依据AuthenticationTrustResolver判断当前登录的用户是否是匿名用户。

<div>
  username : <sec:authentication property="name"/>
  |
  authorities: <sec:authentication property="authorities" var="authorities" scope="page"/>
<c:forEach items="${authorities}" var="authority">
  ${authority.authority}
</c:forEach>
</div>
        

当用户访问系统时,就会看到如下信息,这时他还没有进行登录。

匿名登录

图 17.1. 匿名登录


这里显示的是分配给所有未登录用户的一个默认用户名roleAnonyMous,拥有的权限是ROLE_ANONYMOUS。我们可以看到系统已经把匿名用户当做了一个合法有效的用户进行处理,可以获得它的用户名和拥有的权限,而不需判断SecurityContext中是否为空。

实际上,我们完全可以把匿名用户像一个正常用户那样进行配置,我们可以在配置文件中直接使用ROLE_ANONYMOUS指定它可以访问的资源。

<http auto-config='true'>
    <intercept-url pattern="/" access="ROLE_ANONYMOUS" />
    <intercept-url pattern="/admin.jsp" access="ROLE_ADMIN" />
    <intercept-url pattern="/**" access="ROLE_USER" />
</http>
        

不过,为了更明显的将匿名用户与系统中的其他用户区分开,我们推荐在配置时尽量使用IS_AUTHENTICATED_ANONYMOUSLY来指定匿名用户可以访问的资源。

17.2. 修改默认用户名

我们通常可以看到这种情况,当一个用户尚未登录系统时,在页面上应当显示用户名的部分显示的是“游客”。这样操作更利于提升客户体验,他看到自己即使没有登录也可以使用“游客”的身份享受系统的服务,而且使用了“游客”作为填充内容,也避免了原本显示用户名部分留空,影响页面布局。

如果没有匿名登录的功能,我们就被迫要在所有显示用户名的部分,判断当前用户是否登录,然后根据登录情况显示登录用户名或默认的“游客”字符。匿名登录功能帮我们解决了这个问题,既然未登录用户都拥有匿名用户的身份,那么在显示用户名时就不必去区分用户登录状态,直接显示当前权限主体的名称即可。

我们需要做的只是为匿名设置默认的用户名而已,默认的名称roleAnonymous可以通过配置文件中的anonymous元素修改。

<http auto-config='true'>
    <intercept-url pattern="/" access="IS_AUTHENTICATED_ANONYMOUSLY" />
    <intercept-url pattern="/admin.jsp" access="ROLE_ADMIN" />
    <intercept-url pattern="/**" access="ROLE_USER" />
    <anonymous username="Guest"/>
</http>
        

这样,匿名用户的默认名称就变成了“Guest”,我们在页面上依然使用相同的taglib显示用户名即可。

修改匿名用户名称

图 17.2. 修改匿名用户名称


17.3. 匿名用户的限制

虽然匿名用户无论在配置授权时,还是在获取权限信息时,都与已登录用户的操作一模一样,但它应该与未登录用户是等价,当我们以匿名用户的身份进入“/”后,点击admin.jsp链接,系统会像处理未登录用户时一样,跳转到登录用户,而不是像处理以登录用户时显示拒绝访问页面。

但是匿名用户与未登录用户之间也有很大的区别,比如,我们将“/”设置为不需要过滤器保护,而不是设置匿名用户。

<http security="none" pattern="/"/>

<http auto-config='true'>
    <intercept-url pattern="/" access="IS_AUTHENTICATED_ANONYMOUSLY" />
    <intercept-url pattern="/admin.jsp" access="ROLE_ADMIN" />
    <intercept-url pattern="/**" access="ROLE_USER" />
</http>
        

security="none"表示当我们访问“/”时,是不会使用任何一个过滤器去处理这个请求的,它可以实现无需登录即可访问资源的效果,但是因为没有使用过滤器对请求进行处理,所以也无法利用安全过滤器为我们带来的好处,最简单的,这时SecurityContext内再没有保存任何一个权限主体了,我们也无法从中取得主体名称以及对应的权限信息。

跳过过滤器的情况

图 17.3. 跳过过滤器的情况


因此,使用security="none"忽略所有过滤器会提升性能,而是用匿名登录功能可以实现权限操作的一致性,具体应用时还需要大家根据实际情况自行选择了。

实例在ch107。