`

Spring Security实战(一)-- 基于数据库的权限认证

阅读更多

前言

 

Spring MVC的项目中,可以采用Spring 拦截器做权限控制,具体使用方法可以参考另一篇博文《Spring拦截器。使用Spring 拦截器做权限控制最繁琐的就是需要自己实现用户、角色、权限管理,换到另一个系统又需要重复做一次。庆幸的是Spring Security可以帮我们实现用户、角色、权限管理,让研发人员从这些重复工作中解放出来,简化开发流程。

 

Spring Security的用户、角色、权限管理可以是基于内存、文件、数据库、LDAP等,但我们常用的还是数据库,这里以mysql数据库为例进行讲解。

 

现在一般有两种常规方式实现Spring Bean配置:xml配置方式,java配置方式,另外还是Spring Boot简化配置方式,其实可以理解为java方式的升级版。这里以xml配置方式进行讲解,后面有时间再补充一个Spring boot版本的github地址。

 

Spring Security不仅可以在web层根据链接规则拦截请求做权限控制(类似于spring 拦截器),还可以在其他业务层、dao层等通过注解拦截方法调用做方法级别的权限控制(本质上也可以通过spring aop自己实现)。本次总结主要针对web层的不同链接规则进行不同的权限控制,讲解过程大致分为以下几个步骤:

1Spring Security相关jar

2Spring Security xml配置

3Spring Security数据库认证配置

4Spring Security相关数据库表创建

5demo测试

 

Spring Security相关jar

 

本次demo搭建,采用的是Spring MVC+Freemaker+Spring Security。为了不占用过多篇幅,这里只列出Spring Security相关jarMaven配置,其他jarMaven配置详见文章末尾本次demo搭建的github地址。

 

 
            <dependency>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-web</artifactId>
                <version> 4.1.0.RELEASE </version>
            </dependency>
            <dependency>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-config</artifactId>
                <version>4.1.0.RELEASE </version>
            </dependency>

 

 

这里使用的Spring Security版本为4.1.0.RELEASE,到目前为止最新的版本为5.0.0,可以根据项目需要进行选择。

2Spring Security xml配置

 

Spring Security xml配置,主要配置两个xml文件:web.xmlSpring Security相关bean xml配置文件。首先来看web.xml配置内容,这里只列出Spring Security相关配置,其他配置详见文章末尾github demo地址。

 

 

    <!-- Spring Secutiry 过滤器链配置 -->
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

 

 

 

这里名称必须设置为springSecurityFilterChain,否则无法被识别。DelegatingFilterProxySpring Security拦截入口,该过滤器链包含多个Filter,每个Filter有各自不同的职责。有些属于固定Filter,每次请求都会执行,有些是可选Filter可以根据Spring Security的配置自由选择需要的FilterSpring Security支持的Filiter列表以及顺序,可以在SecurityFilters.java中看到:

 

enum SecurityFilters {
    FIRST(-2147483648),
    CHANNEL_FILTER,
    SECURITY_CONTEXT_FILTER,
    CONCURRENT_SESSION_FILTER,
    WEB_ASYNC_MANAGER_FILTER,
    HEADERS_FILTER,
    CSRF_FILTER,
    LOGOUT_FILTER,
    X509_FILTER,
    PRE_AUTH_FILTER,
    CAS_FILTER,
    FORM_LOGIN_FILTER,
    OPENID_FILTER,
    LOGIN_PAGE_FILTER,
    DIGEST_AUTH_FILTER,
    BASIC_AUTH_FILTER,
    REQUEST_CACHE_FILTER,
    SERVLET_API_SUPPORT_FILTER,
    JAAS_API_SUPPORT_FILTER,
    REMEMBER_ME_FILTER,
    ANONYMOUS_FILTER,
    SESSION_MANAGEMENT_FILTER,
    EXCEPTION_TRANSLATION_FILTER,
    FILTER_SECURITY_INTERCEPTOR,
    SWITCH_USER_FILTER,
LAST(2147483647);

 

 

每个常量对应一个Filter,对照关系表为(来自Spring Security官网http://projects.spring.io/spring-security/):



 

 

我们可以继承这些Filter实现自己的自定义需求,但首先需要知道这些filter的具体功能是什么,这里只对几个常用的filter进行讲解:

 

1SecurityContextPersistenceFilter

 

用途一,在执行其他过滤器之前,率先判断用户的session中是否已经存在一个SecurityContext了。如果存在,就把SecurityContext拿出来,放到SecurityContextHolder中,供Spring Security的其他部分使用。如果不存在,就创建一个SecurityContext出来,还是放到SecurityContextHolder中,供Spring Security的其他部分使用。有点类似HandlerInterceptor接口的preHandle方法。

 

用途二,在所有过滤器执行完毕后,清空SecurityContextHolder,因为SecurityContextHolder是基于ThreadLocal的,如果在操作完成后清空ThreadLocal,会受到服务器的线程池机制的影响。有点类似HandlerInterceptor接口的afterCompletion方法。

 

2LogoutFilter

 

只处理注销请求,结合Spring Security http配置进行更改:

 

<security:logout logout-success-url="/login?logout"/>

 

用途是在用户发送注销请求时,销毁用户session,清空SecurityContextHolder

然后重定向到注销成功页面。可以与rememberMe之类的机制结合,在注销的同时清空用户cookie

 

3AbstractPreAuthenticatedProcessingFilter

 

处理form登陆的过滤器,与form登陆有关的所有操作都是在此进行的。这个请求应该是用户使用form登陆后的提交地址。

此过滤器执行的基本操作时,通过用户名和密码判断用户是否有效,如果登录成功就跳转到成功页面;(可能是登陆之前访问的受保护页面,也可能是默认的成功页面),如果登录失败,就跳转到失败页面。Spring Security http配置方式为:

 

<security:form-login
                    login-page='/login'
                    default-target-url="/welcome"
                    authentication-failure-url="/login?error"
                    username-parameter="username"
                    password-parameter="password"/>

 

 

 

4BasicAuthenticationFilter

 

此过滤器用于进行basic验证,功能与AuthenticationProcessingFilter类似,只是Basic验证方式相比较而言用的不是太多,默认会对密码进行base64加密。Spring Security http配置方式为:

 

<security:http auto-config="true"> 
    <!-- <security:form-login login-page="/login.jsp"/>--> 
    <security:http-basic/> 
    <security:logout logout-success-url="/login.jsp" invalidate-session="true"/> 
    <security:intercept-url pattern="/login.jsp*" filters="none"/> 
    <security:intercept-url pattern="/admin.jsp*" access="ROLE_ADMIN"/> 
    <security:intercept-url pattern="/index.jsp*" access="ROLE_USER,ROLE_ADMIN"/> 
    <security:intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN"/> 
</security:http>

 

 

注意:需要注释掉login-page,因为Basic验证会提供默认登陆页面。

 

5SecurityContextHolderAwareRequestFilter

 

此过滤器用来包装客户的请求。通过查看其源码可以发现其doFilter方法中会创建一个包装类型SecurityContextHolderAwareRequestWrapperServletRequest对象进行包装,主要实现了servlet api的一些接口方法isUserInRolegetRemoteUser,为后续程序提供一些额外的数据。即可以从request对象中获取到用户信息。

 

6RememberMeAuthenticationFilter

 

作用为:当用户没有登录而直接访问资源时, cookie里找出用户的信息, 如果Spring Security能够识别出用户提供的remember me cookie, 用户将不必填写用户名和密码, 而是直接登录进入系统. 它先分析SecurityContext里有没有Authentication对象. 如果有, 则不做任何操作, 直接跳到下一个过滤器. 如果没有, 则检查request里有没有包含remember-mecookie信息. 如果有, 则解析出cookie里的验证信息, 判断是否有权限。Spring Security http配置方式为:

 

<http>
...
<remember-me key="myAppKey"/>
</http>

 

 

7AnonymousAuthenticationFilter

 

用于支持Spring Security的匿名访问,适用于 一些公共资源希望所有人都可以看到。对于匿名访问的用户,Spring Security支持为其建立一个匿名的AnonymousAuthenticationToken存放在SecurityContextHolder中,这就是所谓的匿名认证。这样在以后进行权限认证或者做其它操作时我们就不需要再判断SecurityContextHolder中持有的Authentication对象是否为null了,而直接把它当做一个正常的Authentication进行使用就OK了。不现在登录页配置:

 

<intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
等同于
<http pattern="/login.jsp" security="none">

 

 

自定义匿名配置方式:

 

<bean id="anonymousAuthFilter"
         class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
<property name="key" value="foobar"/>
<property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS"/>
</bean>
 
<bean id="anonymousAuthenticationProvider"
         class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
<property name="key" value="foobar"/>
</bean>
 
security:intercept-url pattern='/common**' access='ROLE_ANONYMOUS'/>

 

 

通过上述配置,可以实现对没有权限的用户开发/common**下所有资源。

 

8ExceptionTranslationFilter

 

此过滤器的作用是处理中FilterSecurityInterceptor抛出的异常,然后将请求重定向到对应页面,或返回对应的响应错误代码。

 

指定不同的异常跳转到不同的页面配置:

 

<bean id="exceptionTranslationFilter"
class="org.springframework.security.web.access.ExceptionTranslationFilter">
<property name="authenticationEntryPoint" ref="authenticationEntryPoint"/>
<property name="accessDeniedHandler" ref="accessDeniedHandler"/>
</bean>
 
<bean id="authenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/login.jsp"/>
</bean>
 
<bean id="accessDeniedHandler"
         class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
<property name="errorPage" value="/accessDenied.htm"/>
</bean>

 

 

9FilterSecurityInterceptor

 

用户的权限控制都包含在这个过滤器中,主要逻辑在父类AbstractSecurityInterceptor中进行处理。

功能一:如果用户尚未登陆,则抛出AuthenticationCredentialsNotFoundException“尚未认证异常”。

功能二:如果用户已登录,但是没有访问当前资源的权限,则抛出AccessDeniedException“拒绝访问异常”。

功能三:如果用户已登录,也具有访问当前资源的权限,则放行。

 

Spring Security 过滤器链配置

 

上一节讲述了Spring Security支持的标准Filter列表,Spring Security 过滤器链配置:其实就是把这些Filiter加入到过滤器链中。本次demo中的配置内容:

 

<security:http auto-config="true">
        <!--静态资源和登陆页面不做限制-->
        <security:intercept-url pattern="/css/**" access="permitAll" />
        <security:intercept-url pattern="/login**" access="permitAll" />
 
        <!--只能ADMIN角色访问-->
        <security:intercept-url pattern="/admin**" access="hasRole('ROLE_ADMIN')" />
 
        <!--通过验证的用户都可以到达这个页面,注意isAuthenticated()带括号-->
        <security:intercept-url pattern="/welcome**" access="isAuthenticated()" />
 
        <!--其他页面USER角色都可以访问-->
        <security:intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
        <security:form-login
                    login-page='/login'
                    default-target-url="/welcome"
                    authentication-failure-url="/login?error"
                    username-parameter="username"
                    password-parameter="password"/>
 
        <!--没有权限错误页面-->
        <security:access-denied-handler error-page="/nopermit"/>
 
        <security:logout
                logout-success-url="/login?logout"/>
        <security:csrf />
    </security:http>

 

 

其他配置很好理解,重点说下auto-config="true"配置,就相当于

 

  <http>
    <form-login />
    <http-basic />
    <logout />
  </http>

 

也就是使用了默认的过滤器,如果需要自定义Filter,可以继承上一节中的Filter 自己实现doFilter方法。

 

Spring Security数据库认证配置

 

Spring Security认证主要通过AuthenticationManagerAuthenticationProvider实现,AuthenticationProvider有多种实现,本次demo采用默认的数据库认证方式,配置如下:

 

<security:authentication-manager>
        <security:authentication-provider user-service-ref='myUserDetailsService'/>
    </security:authentication-manager>

 

这里的myUserDetailsService 采用的是默认的JdbcDaoImpl,配置如下:

 

<bean id="myUserDetailsService"
                class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
        <property name="dataSource" ref="dataSource"/>
</bean>
 

 

 

JdbcDaoImpl依赖一个数据源“dataSource” bean,本demo采用的是mysql数据源,配置如下:

 

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
              <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
              <property name="url" value="jdbc:mysql:loadbalance://192.168.148.95:3306/security_test?useUnicode=true&amp;characterEncoding=UTF8"/>
              <property name="username" value="root"/>
              <property name="password" value="123456"/>
       </bean>

 

 

Spring Security相关数据库表创建

 

通过阅读JdbcDaoImpl源码可以发现,Spring Security默认情况下需要在数据库中创建用户表和权限表:

 

private String authoritiesByUsernameQuery = "select username,authority from authorities where username = ?";
private String usersByUsernameQuery = "select username,password,enabled from users where username = ?";

 

 

默认用户表为usersmore权限表为:authorities。本次demo的建表语句为:

 

-- ----------------------------
-- Table structure for `authorities`
-- ----------------------------
DROP TABLE IF EXISTS `authorities`;
CREATE TABLE `authorities` (
  `username` varchar(50) COLLATE utf8_bin NOT NULL,
  `authority` varchar(50) COLLATE utf8_bin NOT NULL,
  UNIQUE KEY `ix_auth_username` (`username`,`authority`),
  CONSTRAINT `fk_authorities_users` FOREIGN KEY (`username`) REFERENCES `users` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
 
-- ----------------------------
-- Records of authorities
-- ----------------------------
INSERT INTO `authorities` VALUES ('mysql1', 'ROLE_ADD');
INSERT INTO `authorities` VALUES ('mysql1', 'ROLE_ADMIN');
INSERT INTO `authorities` VALUES ('mysql1', 'ROLE_SELECT');
INSERT INTO `authorities` VALUES ('mysql1', 'ROLE_USER');
INSERT INTO `authorities` VALUES ('mysql2', 'ROLE_SELECT');
INSERT INTO `authorities` VALUES ('mysql2', 'ROLE_USER');
 
-- ----------------------------
-- Table structure for `users`
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `username` varchar(50) COLLATE utf8_bin NOT NULL,
  `password` varchar(50) COLLATE utf8_bin NOT NULL,
  `enabled` tinyint(1) NOT NULL,
  PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
 
 

 

 

从表结构设计不难看出,一个用户可以对应多个角色权限,在为每个新用户分配权限时需要选择多个角色权限,难免有些重复工作。这个问题可以通过开启分组功能解决,如果开启分组功能,同时需要创建分组相关的三张表。一个用户可以对应多个分组,一个分组可以对应多个角色权限。关于分组权限控制这里不再详细讲述。

 

这里采用的完全是Spring Security默认处理方式,根据自己的实际业务需要可以继承JdbcDaoImpl,重写相关sql语句从自己的用户表、角色权限表获取用户信息。

 

demo测试

 

通过上配置即可完成本次demoSpring Security的引入,最终demo的代码已上传至githubhttps://github.com/gantianxing/spring-security。下载代码后,采用jdk1.8+tomcat8环境部署,启动程序。访问http://localhost/,默认会跳转到登陆页面:



 

可以使用msyql1mysql2mysql3(密码都是123456)三个账号登陆,进行权限测试。也可以自己在上述users表、authorities表中创建其他账号权限进行测试。 

 

 转载请注明出处:

 http://moon-walker.iteye.com/blog/2395270

  • 大小: 108.8 KB
  • 大小: 6.6 KB
0
0
分享到:
评论

相关推荐

    Spring Security实战例子

    Spring Security实战例子资源里面有4个小项目,都是利用maven搭建的。数据库要建立一个security的表

    基于SpringBoot+SpringSecurity的RBAC管理系统源码+数据库+项目说明.zip

    这是一款基于SpringBoot+SpringSecurity的RBAC权限管理系统。原本只想着做成基于SpringSecurity的权限管理系统,但随着功能的增加感觉有些刹不住车了,之后可能会往后台管理系统方向发展。无任何重度依赖,非常适合...

    spring-boot示例项目

    Spring Boot简化了基于Spring的应用开发,通过少量的代码就能创建一个独立的、产品级别的Spring应用。 Spring Boot为Spring平台及第三方库提供开箱即用的设置,这样你就可以有条不紊地开始。多数Spring Boot应用只...

    SpringBoot最全企业级博客前后端视频教程

    11-3,11-4 -Spring Security 实战-前后台编码 第12章 博客系统的整体框架实现 12-1 -整体的需求回顾 12-2 -后台整体控制层、API 实现 12-3 -前台整体布局实现 12-4 -API 讲解 第13章 博客系统的用户管理实现...

    毕设新作-基于spring-mvc框架实现仓库管理系统完整源码+项目说明.zip

    1、通过spring security实现的RBAC权限的模型基础上实现权限、角色、资源的管理,实现根据数据库动态分配权限的功能,对未登录及未授权的操作进行拦截。在用户管理中心,管理员可添加用户代替了自行注册方式。 2、...

    Springboot+Mybatis-plus+ SpringMvc+Shiro+Redis企业级报表后台管理系统

    报表后端采用技术: SpringBoot整合SSM(Spring+Mybatis-plus+ SpringMvc),spring security 全注解式的权限管理和JWT方式禁用Session,采用redis存储token及权限信息 报表前端采用Bootstrap框架,结合Jquery Ajax,...

    基于springboot开发众筹平台前后台管理系统【完整源码+运行指导】

    本项目是一套基于springboot等主流的技术框架开发的众筹平台系统; 项目整体包含前、后台两...- 权限安全:SpringSecurity + oauth2 - 接口文档:swagger2 - 开发软件:eclipse/idea - html + vue + js + jQuery + ajax

    基于Spring boot博客的下载地址(imooc实战)

    https://github.com/codingZhangxin/BootBlog, imooc实战课程项目-基于Spring boot博客的搭建教程 技术栈 后端: SpringBoot+ElasticSearch+SpringSecurity 前端: Thymeleaf/Bootstrap/jQuery 数据库:MySQL/...

    Spring Cloud 实战项目

    无状态统一权限认证的解决方案,实现了异常和日志的统一管理,实现了MQ落地保证100%到达的解决方案。 核心框架:springcloud Edgware全家桶 安全框架:Spring Security Spring Cloud Oauth2 分布式任务调度:...

    基于Java开发的一物一码溯源防伪演示系统源码+sql数据库.zip

    基于Java开发的一物一码溯源防伪演示系统源码+sql数据库.zip 【技术栈】 前端采用Vue、Element UI。 后端采用Spring Boot、Spring Security、Redis & Jwt。 权限认证使用Jwt,支持多终端认证系统。 【功能系统演示】...

    基于springboot实现的图书管理系统【源码+数据库】

    登录验证和用户权限: SpringSecurity 三、系统划分与功能 系统包含两种角色:管理员、读者。主要功能如下: 登录、注销、修改密码 管理员对图书信息的增删改查、查看读者、查看借阅记录 读者对图书信息的查看查询、...

    SpringBoot+Security+Vue前后端分离开发权限管理系统

    SpringSecurity5+Element?UI+Vue?Admin?Template+蚂蚁可视化AntV?等技术栈开发的项目,采用分布式,多模块,前后端分离开发。包括图形展示、权限管理、用户管理等功能。【后端技术】技术说明Spring?Boot2MVC框架?...

    基于springboot+vue前后端分离的仓库管理系统源码+数据库.zip

    整合了springSecurity实现了,用户的认证和权限的管理,整合了Redis在权限认证时使用的redis缓存了权限的用户角色权限的数据。通过MybatisPlus大大提高了了工作效率。使用了快递鸟的第三方接口实现了物流跟踪(免费...

    基于springcloud+vue+oAuth2.0全家桶实战并实现前后端分离模拟商城.zip

    基于springcloud+vue+oAuth2.0全家桶实战并实现前后端分离模拟商城.zip 功能点: 模拟商城,完整的购物流程、后端运营平台对前端业务的支撑,和对项目的运维,有各项的监控指标和运维指标。 技术点: 核心技术为...

    spring-boot-demo_xkcoding.tar.gz

    job(分布式定时任务)、swagger(API接口管理测试)、security(基于RBAC的动态权限认证)、SpringSession(Session共享)、Zookeeper(结合AOP实现分布式锁)、RabbitMQ(消息队列)、Kafka(消息队列)、websocket(服务端推送...

    spring cloud + vue + oAuth2.0全家桶实战,前箱分离模拟商城项目(源码)

    Spring Cloud 实战项目 项目介绍 功能点: 模拟商城,完整的购物流程、后端运营平台对前端业务的支撑,和对项目的运维,有各项的监控指标和运维指标。 技术点: 核心技术为springcloud+vue两个全家桶实现,采取了...

    spring boot demo 是一个用来深度学习并实战 spring boot 的项目

    该项目已成功集成 actuator(监控)、admin(可视化监控)、...job(分布式定时任务)、swagger(API接口管理测试)、security(基于RBAC的动态权限认证)、SpringSession(Session共享)、Zookeeper(结合AOP实现分布式锁)、Ra

    企业中台后台权限SpringBoot2+Vue实战

    该互联网实战项目是基于 Spring Boot 2+ SpringSecurity5+Element UI+Ant Design Pro Vue+可视化AntV 等技术栈开发的项目,采用多模块前后端分离开发。包括图形展示、权限管理、用户管理等功能,用于研发企业级中...

    2019品优购.txt

    技术选型 前端:angularJS + Bootstrap 后台:SSM( springmvc+...SpringSecurity, 跨域:cro s 支付:微信扫描 短信验证:阿里大于 密码加密:BCrypt 富文本:KindEditor 事务:声明式事务 任务调度:spring task

    Spring Boot带前后端 渐进式开发企业级博客系统

    Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架, 在企业级应用中被广泛使用。本章节不会对该框架做深入探讨,仅从基于角色的权限管理角度,来实现对系统的权限...

Global site tag (gtag.js) - Google Analytics