SpringSecurity入门

导语

互联网已经成为了我们生活一部分,但是安全问题频发,身份认证变得更为复杂。如何让这一部分更安全?如何让这一部分的身份验证变得更简单?下面将介绍Spring全家桶中的安全框架SpringSecurity快速入门及使用,来解决身份验证问题.
springsecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作.下面使用实现一个springsecurity案例

创建maven工程(war包) 导入pom依赖
<!--Spring和SpringSecurity依赖-->
    <dependencies>
        <!--springmvc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
    
        <!-- spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
    
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
    
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
    
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
    
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
    
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
    
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.6</version>
        </dependency>
    
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.6</version>
        </dependency>
    
        <!--SpringSecurity相关依赖-->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-cas</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>
    
        <!-- MySql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.45</version>
        </dependency>
        
    	<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>  
			<scope>provided</scope>
		</dependency>
		
        <!--数据连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.13</version>
        </dependency>
    </dependencies>
    <build>
		<plugins>
			<!-- 配置Tomcat插件 -->
			<plugin>
				<groupId>org.apache.tomcat.maven</groupId>
				<artifactId>tomcat7-maven-plugin</artifactId>
				<configuration>
					<port>80</port>
					<!-- http://127.0.0.1:{port}/{path} -->
					<path>/</path>
				</configuration>
			</plugin>
		</plugins>
	</build>
web.xml配置
<!-- 编码过滤器 -->
  <filter>
    <filter-name>characterEncoding</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>

  <filter-mapping>
    <filter-name>characterEncoding</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <!--//End 编码过滤器 -->
  
  <!--springsecurity过滤器,做资源权限的拦截和验证-->
 <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>
  
  <!-- SpringMVC -->
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring/springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>*.html</url-pattern>
  </servlet-mapping>
springmvc.xml配置
<?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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

	<!-- 包扫描 -->
	<context:component-scan base-package="com.shemuel.controller" />


	<!-- 视图解析器 -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	    <property name="prefix" value="/WEB-INF/view/" />
	    <property name="suffix" value=".jsp" />
	</bean>

	<!--引入SpringSecurity配置文件-->
	<!--<import resource="spring-security.xml" />-->
	<import resource="spring-security.xml"/>
</beans>
springsecurity.xml 配置(最终配置,后面会讲每个部分什么意思)
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
             xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             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-4.2.xsd ">
	
	
	<!-- 公共资源取消授权拦截 -->
	<!-- <http pattern="/images/**" security="none"/>
	
	<http pattern="/register" security="none"/>
	
	<http pattern="/loginout" security="none"/> -->
	<http pattern="/login.html" security="none"/>
	<http pattern="/login/fail.html?error" security="none"/>
	<!--
	 auto-config表示自动引入springsecurity相关过滤器
	 user-expression属性表示是否使用 表达式 
	 -->
	<http auto-config="true" use-expressions="true">
    	<!--配置需要过滤哪些页面,所有带有user的请求都需要ROLE_ADMIN权限-->
    	<intercept-url pattern="/user/**" access="hasRole('ROLE_ADMIN')" />
    	<form-login login-page="/login.html"
            default-target-url="/user/list.html"
            authentication-failure-url="/login/fail.html?error"
            username-parameter="username"
            password-parameter="password"
            always-use-default-target="true" />
            
        <!--禁用CSRF-->
		<csrf disabled="true"/>
    	
	</http>

	

	<!--授权认证管理器-->
	<authentication-manager>
		<authentication-provider>
		
			<!-- 引用已经配置的加密算法 -->
			<password-encoder ref="encoder"></password-encoder>
			<!-- 对指定数据库表里的用户进行授权认证 -->
			<jdbc-user-service data-source-ref="dataSource" users-by-username-query="select username, password, enabled from users where username=?" />
		</authentication-provider>
	</authentication-manager>
	
	<!-- 数据库连接池 -->
	<beans:bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
	      destroy-method="close">
	    <beans:property name="url" value="jdbc:mysql://127.0.0.1:3306/security?characterEncoding=utf8" />
	    <beans:property name="username" value="root" />
	    <beans:property name="password" value="root" />
	    <beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
	    <beans:property name="maxActive" value="10" />
	    <beans:property name="minIdle" value="5" />
	</beans:bean>
	
	<!-- 配置加密算法 -->
	<beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
        <beans:constructor-arg name="strength" value="9" /><!-- 加密的密码长度9 -->
	</beans:bean>
	
</beans:beans>
创建UserController

创建用户管理的Controller,并加入用户列表功能

package cn.itcast.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping(value = "/admin/user")
public class UserController {

    /***
     * 用户管理
     * @return
     */
    @RequestMapping(value = "/list")
    public String list(){
        return "user_list";
    }
}
在/WEB-INF/view/下创建user_list.jsp

为了演示效果,我们这里整点假数据展示

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>欢迎来到SpringSecurity的世界</title>
</head>
<body>
    欢迎来到SpringSecurity的世界!<br />
    <table>
        <tr>
            <td>用户ID</td>
            <td>姓名</td>
            <td>年龄</td>
        </tr>
        <tr>
            <td>1</td>
            <td>张三</td>
            <td>王五</td>
        </tr>
        <tr>
            <td>2</td>
            <td>张三2</td>
            <td>王五</td>
        </tr>
        <tr>
            <td>3</td>
            <td>张三3</td>
            <td>王五</td>
        </tr>
        <tr>
            <td>4</td>
            <td>张三4</td>
            <td>王五</td>
        </tr>
    </table>
</body>
</html>
实现对/user开始的请求拦截

在spring-security.xml中配置拦截信息和授权认证管理器

<http auto-config="true" use-expressions="true">
    <!--所有带有admin的请求都需要ROLE_ADMIN权限-->
    <intercept-url pattern="/user/**" access="hasRole('ROLE_ADMIN')" />
</http>

<!--授权认证管理器-->
<authentication-manager>
</authentication-manager>

http结点主要配置要拦截的url相关权限规则和处理方案。

auto-config =true:默认会配置多个SpringSecurity相关过滤器,如果不配,就不能正常使用SpringSecurity相关功能。

use-expressions:是否使用SpELl表达式。

,pattern表示要拦截的路径,可以用通配符表示, * * 表示所有路径。 access表示对应地址访问所需的权限,如果use-expressions="false"access="hasRole(‘ROLE_ADMIN’)"这里的hasRole就可以去掉,我们后面都会设置成false,直接去掉这里的hasRole方便一点。ROLE_ADMIN表示ADMIN角色,这列角色自定义,可以随意定义什么角色,不过注意,这里必须得大写。

发布测试

用tomcat发布测试,端口号根据你本机情况开放,我这里端口是80,可以省略
访问 localhost/user/list.html的时候跳转到了一个登陆界面,说明拦截配置生效了。
这是springsecurity自带的登录页面,应该是用代码动态生成的,后面可以改成自己的,

添加授权用户

接着我们为上面登陆那里添加授权用于,允许他们登陆。修改spring-security.xml,在authentication-manager结点下加入如下代码:

<authentication-provider>
    <!--硬编码方式提供账号密码-->
    <user-service>
        <user name="admin" authorities="ROLE_ADMIN" password="123456" disabled="false" />
    </user-service>
</authentication-provider>

这里提供了用户名为admin 密码123456 角色为ROLE_ADMIN的用户,这里的角色必须和上面http里配置的角色保持一致,否则仍然五权限访问。disabled=false表示不禁用也就是启用。这时候我们就可以通过该账号登录访问了。
登录后我们就可以访问http://localhost/user/list.html了

Spring Security常用配置

基于上面的案例我们继续学习SpringSecurity相关知识。

取消安全校验

我们网站中常常会有一些静态资源或者不需要校验权限的地址,例如注册和登录,我们在webapp下创建一个images文件夹,在里面放一张图片1.png。像这些地址或者静态资源我们如何取消权限校验呢?在spring-security.xml中加入如下代码:

<!--不需要过滤的静态资源和开放连接-->
<http pattern="/images/**" security="none" />
<http pattern="/login.shtml" security="none" />
<http pattern="/login/fail.shtml" security="none" />

这时候 http://localhost/images/1.jpg 就可以访问了。

自定义登录页面

刚才那个登录页面不太美观,我们能不能让登录地址跳转到指定页面呢?

首先我们创建一个登录页面

/WEB-INF/view/login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>登录</title></head>
<body>
欢迎登录!我自己的登录页面,后期可进行美化.
<form name='f' action='/login' method='POST'>
    <table>
        <tr>
            <td>用户名:</td>
            <td><input type='text' name='username' value=''></td>
        </tr>
        <tr>
            <td>密码:</td>
            <td><input type='password' name='password'/></td>
        </tr>
        <tr>
            <td colspan='2'><input name="submit" type="submit" value="Login"/></td>
        </tr>
    </table>
</form>
</body>
</html>

LoginController

package cn.itcast.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class LoginController {

    /***
     * 登录
     * @return
     */
    @RequestMapping(value = "/login")
    public String login(){
        return  "login";
    }
}

修改spring-security.xml 在http结点中加入如下代码:

<!--自定义登录-->
<form-login login-page="/login.shtml"
            default-target-url="/user/list.shtml"
            authentication-failure-url="/login/fail.html?error"
            username-parameter="username"
            password-parameter="password"
            always-use-default-target="true" />
  • login-page:自定义登录页url,默认为/login
  • default-target-url:默认登录成功后跳转的url
  • authentication-failure-url: 登录失败后跳转的url
  • username-parameter:用户名的请求字段 默认为userName
  • password-parameter:密码的请求字段 默认为password
  • always-use-default-target:是否始终使用默认的地址,即登录成功后是否总是跳转到默认地址

再次登录,发现报403错误(如下),是因为SpringSecurity这里做了防csrf攻击校验,我们禁用csrf校验即可。

HTTP Status 403 – Forbidden
Type Status Report
Message Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.
Description The server understood the request but refuses to authorize it.
Apache Tomcat/8.5.16

在http结点加入

<!--禁用CSRF-->
<csrf disabled="true" />
登录错误信息处理

在LoginController中加一个错误处理方法

/***
 * 登录失败
 * @return
 */
@RequestMapping(value = "/login/fail")
public String loginfail(@RequestParam(value = "error",required = false)String error, Model model){
    if(error!=null){
        model.addAttribute("msg","账号或者密码不对!");
    }
    return  "login";
}

在登录的jsp回显错误

<tr>
    <td colspan='2'>
        ${msg}<br />
        <input name="submit" type="submit" value="Login"/>
    </td>
</tr>
数据库中的用户账号密码登录

前面我们一直是写死的用户账号和密码,而真实环境中基本都是从数据库获取账号密码,这个如何实现?

首先创建一个数据库叫springsecurity,接着创建两张表,一张是users表,存放用户信息,另一张是authorities表,存放用户角色信息。

  CREATE TABLE `users` (
      `username` varchar(50) NOT NULL,
      `password` varchar(60) NOT NULL,
      `enabled` varchar(50) NOT NULL,
      PRIMARY KEY (`username`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    INSERT INTO users(username,password,enabled)VALUES('itcast','123456','true');
    


    CREATE TABLE `authorities` (
	  `username` varchar(50) NOT NULL,
	  `authority` varchar(50) NOT NULL,
	  PRIMARY KEY (`username`)
	) ENGINE=InnoDB DEFAULT CHARSET=utf8;

	INSERT INTO authorities(username,authority)VALUES('itcast','ROLE_ADMIN');

然后加入在springsecurity.xml中加数据库连接池配置,上面的最终版配置文件已经有了我这里就不在写了. 如果配置了加密,则数据库里的密码也应该为加密的密码,否则登录失败.
最后登录成功就能看到如下页面了
在这里插入图片描述

参考:传智播客教学视频.
传智博客官网:http://itcast.cn

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章