1、9.1.1 Spring Security整体控制框架9.1.2 Spring Security的过滤器HttpSessionContextIntegrationFilter:将安全上下文记录到将安全上下文记录到Session中。中。LogoutFilter:处理用户注销请求。:处理用户注销请求。AuthenticationProcessingFilter:处理来自:处理来自form的登录。的登录。DefaultLoginPageGeneratingFilter:生成一个默认的登录页面。:生成一个默认的登录页面。BasicProcessingFilter:用于进行:用于进行basic验证。验证
2、。SecurityContextHolderAwareRequestFilter:用来包装客户的请求,为后续程:用来包装客户的请求,为后续程序提供一些额外的数据。例如,序提供一些额外的数据。例如,getRemoteUser()可获得当前登录的用户名。可获得当前登录的用户名。RememberMeProcessingFilter:实现:实现RememberMe功能。功能。AnonymousProcessingFilter:当用户没有登录时,分配匿名帐户的角色。:当用户没有登录时,分配匿名帐户的角色。ExceptionTranslationFilter:处理处理FilterSecurityInter
3、ceptor抛出的异常,然后抛出的异常,然后将请求重定向到对应页面,或返回对应的响应错误代码。将请求重定向到对应页面,或返回对应的响应错误代码。SessionFixationProtectionFilter:防御会话伪造攻击;解决办法是每次用户登录防御会话伪造攻击;解决办法是每次用户登录重新生成一个重新生成一个session。在。在http元素中添加元素中添加session-fixation-protection=none属性即可。属性即可。FilterSecurityInterceptor:实现用户的权限控制。实现用户的权限控制。9.2.1 利用Spring Security提供的登录页面1
4、.web.xml配置文件配置文件【程序清单程序清单9-1】文件名为文件名为web.xmlcontextConfigLocation/WEB-INF/security-context.xmlorg.springframework.web.context.ContextLoaderListenerbokeorg.springframework.web.servlet.DispatcherServletcontextConfigLocation /WEB-INF/servlet-context.xml1boke/springSecurityFilterChainorg.springframework
5、.web.filter.DelegatingFilterProxyspringSecurityFilterChain/*enter.jsp2.配置文件(WEB-INF/security-context.xml)【程序清单【程序清单9-2】文件名为】文件名为security-context.xml 4.登录完成后,获取用户登录名用户认证后,在用户认证后,在MVC 控制器的代码中,获控制器的代码中,获取用户登录名的最简单方法有两种取用户登录名的最简单方法有两种:(1)通过通过MVC方法参数注入的方法参数注入的Principal对象的对象的getName()方法。方法。(2)通过通过MVC方法参数注
6、入的方法参数注入的HttpServletRequest对象的对象的getRemoteUser()方法。方法。9.2.2 使用自制的登录页面1.security-context的修改的修改对对security-context.xml中中HTTP的安全设置做如下修的安全设置做如下修改:改:在在http元素中还可包含一些特殊的子元素。元素中还可包含一些特殊的子元素。默认配置实际是支持匿名访问,匿名设置默认名称默认配置实际是支持匿名访问,匿名设置默认名称roleAnonymous,可以通过,可以通过anonymous子元素定义匿名帐户子元素定义匿名帐户名和角色名。例如,以下规定匿名帐户名为名和角色名。
7、例如,以下规定匿名帐户名为Guest。用来在一段时期内通过用来在一段时期内通过cookie记住登录用记住登录用户,避免重复登录。但在登录表单中要加入户,避免重复登录。但在登录表单中要加入复选框来选择是否记住用户,默认两周内可记住用户。复选框来选择是否记住用户,默认两周内可记住用户。用来避免同一帐户并发登录。用来避免同一帐户并发登录。默认后登录的同名帐户将前面登录的用户踢出系统。默认后登录的同名帐户将前面登录的用户踢出系统。2.自制的登录页面newlogin.jsp 用户登录用户登录 登录名登录名 口口 令令 9.3 使用数据库用户进行认证数据库中含有两个表格,数据库中含有两个表格,u
8、sers表至少含有表至少含有username,password,enabled三个字段;三个字段;authorities表至少含有表至少含有username、authority、id三个字段。其中,三个字段。其中,enabled为为整数,整数,1代表用户有效,代表用户有效,0代表禁用,代表禁用,id采用自采用自动编号。两个表通过动编号。两个表通过username建立关联。一建立关联。一个用户有多个角色时,在个用户有多个角色时,在authority表中要占表中要占多条记录。多条记录。【程序清单程序清单9-4】文件名为文件名为security-context.xml 以上配置中,首先定义了一个用以
9、上配置中,首先定义了一个用Access数据库的数数据库的数据源,据源,Spring Security 的的 JdbcDaoImpl 类使用该类使用该数据源来加载用户信息。最后需要配置认证管理器使数据源来加载用户信息。最后需要配置认证管理器使用该用该 UserDetailsService。另一种办法是直接用如下标记指定另一种办法是直接用如下标记指定JDBC数据源作为认数据源作为认证对象。证对象。9.4 对用户密码进行加密处理9.4.1 Spring Security早期版本的PasswordEncoder在在Spring Security 3.1.0之前版本中之前版本中,为加密和密码验证定义了为
10、加密和密码验证定义了PasswordEncoder接口。该接口安排在接口。该接口安排在org.springframework.security.authentication.encoding包中。包中。public interface PasswordEncoder String encodePassword(String rawPass,Object salt);boolean isPasswordValid(String encPass,String rawPass,Object salt);其中,其中,encodePassword()方法是对原始密码进行加密,采用方法是对原始密码进行加密
11、,采用hash+salt方式,方式,通过通过“盐值盐值”(salt)避免字典攻击。加密后的密码是将原始用户密码和盐值合并避免字典攻击。加密后的密码是将原始用户密码和盐值合并后的内容进行加密后的结果。后的内容进行加密后的结果。isPasswordValid方法是用来验证密码是否正确的,方法是用来验证密码是否正确的,需要提供需要提供3个参数,加密后的密码,原始密码以及盐值。个参数,加密后的密码,原始密码以及盐值。密码加密安全配置 9.4.2 Spring Security3.1.0后新增的PasswordEncoder在在org.springframework.security.crypto包中。
12、包中。与前面的与前面的PasswordEncoder比较,好处是盐值不用比较,好处是盐值不用用户提供,每次随机生成。随机盐确保相同的密码使用户提供,每次随机生成。随机盐确保相同的密码使用多次时,产生的哈希值不同,从而增加了密码破解用多次时,产生的哈希值不同,从而增加了密码破解难度。新接口定义如下:难度。新接口定义如下:public interface PasswordEncoder String encode(String rawPassword);boolean matches(String rawPassword,String encodedPassword);密码加密配置 9.5 关于访
13、问授权表达式.表达式表达式描述描述hasRole(role)hasRole(role)如果角色拥有指定的权限(如果角色拥有指定的权限(rolerole)则返回)则返回truetruehasAnyRole(role1,rolehasAnyRole(role1,role2)2)如果角色拥有列表中任意一个权限则返回如果角色拥有列表中任意一个权限则返回truetrueprincipalprincipal允许直接访问角色对象代表当前用户允许直接访问角色对象代表当前用户authenticationauthentication允许直接访问允许直接访问 Security Security 上下文中的认证对象上
14、下文中的认证对象permitAllpermitAll总是返回总是返回truetruedenyAlldenyAll总是返回总是返回falsefalseisAnonymous()isAnonymous()如果角色是一个如果角色是一个 anonymous anonymous 用户则返回用户则返回truetrueisRememberMe()isRememberMe()如果角色是一个如果角色是一个 remember-me remember-me 用户则返回用户则返回truetrueisAuthenticated()isAuthenticated()如果角色不是如果角色不是 anonymous anony
15、mous 则返回则返回truetrueisFullyAuthenticated()isFullyAuthenticated()如果角色即不是如果角色即不是 anonymous,anonymous,也不是也不是 remember-me remember-me 用户则返回用户则返回truetrue表9-3 授权访问的传统配置与表达式的等价传统配置传统配置表达式表达式ROLE_ADMINROLE_ADMINhasRole(ROLE_ ADMIN)hasRole(ROLE_ ADMIN)ROLE_USER,ROLE_ADMINROLE_USER,ROLE_ADMINhasAnyRole(ROLE_US
16、ER,ROLE_ADMIN)hasAnyRole(ROLE_USER,ROLE_ADMIN)ROLE_ADMIN,IS_AUTHENTICATED_FUROLE_ADMIN,IS_AUTHENTICATED_FULLYLLYhasRole(ROLE_ADMIN)and hasRole(ROLE_ADMIN)and isFullyAuthenticated()isFullyAuthenticated()IS_AUTHENTICATED_ANONYMOUSLYIS_AUTHENTICATED_ANONYMOUSLYpermitAllpermitAllIS_AUTHENTICATED_REMEMBE
17、REDIS_AUTHENTICATED_REMEMBEREDisAnonymous()or isRememberMe()isAnonymous()or isRememberMe()IS_AUTHENTICATED_FULLYIS_AUTHENTICATED_FULLYisFullyAuthenticated()isFullyAuthenticated()9.6 基于注解的方法访问的保护在安全配置文件中要加上如下行:在安全配置文件中要加上如下行:1.使用使用Secured和和PreAuthorize注解符注解符Secured(ROLE_USER)public MyResource getRes(
18、int id)2.使用 PreFilter and PostFilter过滤器 Spring安全支持一组过滤器,用来实现对集合和安全支持一组过滤器,用来实现对集合和数组等对象的过滤。数组等对象的过滤。PreFilter用来对方法调用时的用来对方法调用时的参数进行过滤。参数进行过滤。PostFilter用来对方法的返回结果用来对方法的返回结果进行过滤。进行过滤。PreAuthorize(hasRole(ROLE_USER)PostFilter(hasPermission(filterObject,read)or hasPermission(filterObject,admin)public Li
19、st getAll();9.7 Spring提供的JSP安全标签库 使用使用JSP 标签库,首先要把标签库,首先要把spring-security-taglibs-3.1.0.RC2.jar放到项目的放到项目的classpath下。在下。在 JSP 页面上添加以下声明:页面上添加以下声明:这个标签库包含这个标签库包含3 个标签,分别是个标签,分别是authorize、authentication和和accesscontrollist。要使用要使用JSP安全标签,在配置文件将安全标签,在配置文件将http标记的标记的use-expressions属性设置为属性设置为true:1.authoriz
20、e标签 【说明说明】限定内容只有具有经理角色的用户才可见。限定内容只有具有经理角色的用户才可见。【说明说明】限定内容只有能访问限定内容只有能访问“/manger/first”这个这个URL的用户才可的用户才可见。见。以下代码限制只有用户拥有以下代码限制只有用户拥有ROLE_ADMIN和和ROLE_USER两个角色时,两个角色时,才能显示标签内部内容。才能显示标签内部内容。.而将而将“ifAllGranted”改为改为“ifAnyGranted”,则表示拥有,则表示拥有ROLE_ADMIN,ROLE_USER权限之一时满足条件。权限之一时满足条件。ifNotGranted则则表示不具所指权限满足条件。表示不具所指权限满足条件。2.authentication标签$authority.authority 9.7.2 JSP安全标签的应用举例 Welcome!Author$resource.userId Title$resource.titleName Body$resource.description Delete a href=Logout