spring security入门

spring security 框架简介

功能

  1. Authentication: 认证,就是用户登录
  2. Authorization: 授权,判断用户有什么权限
  3. 安全防护:防止跨站请求,session攻击
  4. 容易结合spring mvc
  5. 缓存支持、会话管理、加密功能、rememberMe功能

缺点

  • 相对于shiro的配置和使用,比较复杂
  • 必须依赖spring 容器,才可运行。shiro依赖性低,不需要依赖任何第三方框架,即可运行
认证过程

在这里插入图片描述

搭建

1、导入pom

spring-core
spring-web
spring-webmvc
spring-security-web
spring-security-config

jstl>jstl
javax.servlet>servlet-api

json工具:com.fasterxml.jackson.core>jackson-databind

可以不使用本地的tomcat,直接在当前pom.xml的目录下命令mvn tomcat:run运行项目
<build>
		<plugins>
			<plugin>
				<groupId>org.apache.tomcat.maven</groupId>
				<artifactId>tomcat7-maven-plugin</artifactId>
				<version>2.1</version>
				<configuration>
					<path>/ssl</path>
					<port>8080</port>
					<server>tomcat9</server>
				</configuration>
			</plugin>
		</plugins>
	</build>

2、配置web.xml

	<!-- 启动spring -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
		classpath:application.xml
		<!-- 加载spring securityxml文件 -->
		classpath:spring-security.xml
		</param-value>
	</context-param>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<!-- 配置springmve 前端控制器servlet -->
	<servlet>
		<servlet-name>springDispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:springmvc.xml</param-value>
		</init-param>
		<!-- 在服务器启动时就启动 -->
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>springDispatcherServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	
	<!-- spring security过滤器链 -->
    <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>
	
	 <!--设置filter编码过滤器,解决中文乱码问题-->
    <filter>
        <filter-name>EncodingFilter</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>EncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

spring和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:context="http://www.springframework.org/schema/context"
               xmlns:aop="http://www.springframework.org/schema/aop"
               xmlns:tx="http://www.springframework.org/schema/tx"
               xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-3.0.xsd
                        http://www.springframework.org/schema/aop
                        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
                        http://www.springframework.org/schema/tx
                        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
                        http://www.springframework.org/schema/mvc
                        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"
                        default-autowire="byName"><!--自动装配(全局)-->
</beans>

注意!!!

spring-security.xml一定要有基本的配置,否则会报异常

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘springSecurityFilterChain’ available

配置spring mvc.xml

	<!-- 扫描controller包 -->
	<context:component-scan base-package="com.lida" />
	<!-- 注解方法配置处理器映射器和处理器适配器 -->
	<!-- 配置这个就自动配置两个器 -->
	<mvc:annotation-driven />

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

	 <!-- 处理静态资源,当有静态资源的请求时,就放行 -->
	 <mvc:default-servlet-handler/>

配置spring-security.xml

<!-- 过滤器链的配置 :1、需要拦截哪些资源 2、有什么资源和什么角色 3、定义登陆认证的方式,httpbasic,formlogin 4、定义登陆页面,定义登录请求地址,出现错误的处理方法 
		主要功能: 检查该次请求是否有权限 -->
	<security:http>

		<!-- 该项配置有顺序性 -->
		<!-- permitAll()允许所有人都可以通过这个请求 isAnonymous()只限定匿名的人可以通过这个请求 -->
		<security:intercept-url pattern="/index"
			access="permitAll()" />
		<security:intercept-url pattern="/userLoginPage"
			access="permitAll()" />
		<!--配置有ROLE_USER角色才可放行   hasAuthority("")判断有无该权限名字-->
		<security:intercept-url pattern="/add"
			access="hasRole('ROLE_USER')" />

		<!-- 拦截所有请求资源,,isFullyAuthenticated()需要被认证才可通过该次请求 -->
		<security:intercept-url pattern="/**"
			access="isFullyAuthenticated()" />


		<!-- 使用HttpBasic方式 -->
		<!-- <security:http-basic /> -->

		<!-- 使用表单登录的方式 -->
		<!-- 自定义配置获取登陆页面的位置,若检测没有认证信息,会重定向到这个请求页面 -->
		<!-- 自定义用户登陆的请求地址,即用户名和密码的存放上传地址 -->
		<!-- 配置验证成功后的访问地址 -->
		<!-- 配置自定义验证成功后的处理逻辑 和验证失败后的 -->
        <!-- 返回页面是同步,,,逻辑处理后返回json,是异步-->
		<security:form-login login-page="/userLoginPage"
			login-processing-url="/userLogin" default-target-url="/successIndex"
			authentication-success-handler-ref="myAuthenticationSuccessHandler"
			authentication-failure-handler-ref="myAuthenticationFailureHandler" />

		<!-- 自定义权限不足的处理配置 权限不足时自动请求这个地址 -->
		<security:access-denied-handler
			error-page="/errorPage" />
		<!-- 关闭scrf -->
		<security:csrf disabled="true" />
	</security:http>

	<!-- 认证配置 认证管理器 1、认证信息的提供方式,账户名、密码,当前用户权限 -->
	<security:authentication-manager>
		<security:authentication-provider>
			<!-- 添加一个用户 后面是角色 硬编码方式 -->
			<security:user-service>
				<security:user name="user" password="password"
					authorities="ROLE_USER" />
				<security:user name="root" password="password"
					authorities="ROLE_root" />
			</security:user-service>
		</security:authentication-provider>

		<!-- 使用自定义的UserDetailsService -->
		<security:authentication-provider
			ref="MyUserDetailsService">
		</security:authentication-provider>
	</security:authentication-manager>

	<bean name="myUserDetailsService" class="com.lida.MyUserDetailsService"></bean>
	<bean name="myAuthenticationSuccessHandler" class="com.lida.MyAuthenticationSuccessHandler"></bean>
	<bean name="myAuthenticationFailureHandler" class="com.lida.MyAuthenticationFailureHandler"></bean>

配置自定义认证提供者:UserDetailsService 和UserDetails

public class MyUserDetailsService implements UserDetailsService {
	// 根据用户名获取用户信息 这里连接数据库
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		// 使用提供的默认的UserDetails实现类User 设置该用户所拥有的权限
		User user = new User("user", "password",
				AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER,ROLE_ROOT"));
		return user;
	}
}
public class MyUserDetails implements UserDetails {
	// 获取该账户的权限
	public Collection<? extends GrantedAuthority> getAuthorities() {
		return null;
	}
	public String getPassword() {
		return null;
	}
	public String getUsername() {
		return null;
	}
	// 该账户是不是不过期
	public boolean isAccountNonExpired() {
		return false;
	}
	// 该账户是不是被锁定
	public boolean isAccountNonLocked() {
		return false;
	}
	// 密码是不是不过期
	public boolean isCredentialsNonExpired() {
		return false;
	}
	// 该账户是不是可用
	public boolean isEnabled() {
		return false;
	}
}

配置验证成功和失败后的处理逻辑

public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
	// 验证成功后的处理逻辑
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws IOException, ServletException {
		// 返回json字符串给前端
		Map<String, Boolean> map = new HashMap<String, Boolean>();
		map.put("success", true);
		// 将对象转为json字符串
		String string = new ObjectMapper().writeValueAsString(map);
		response.setContentType("text/json;charset=utf-8");
		response.getWriter().write(string);
	}
}
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
	// 认证失败后的处理逻辑
	public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException)
			throws IOException, ServletException {
		// 返回json字符串给前端
		Map<String, Boolean> map = new HashMap<String, Boolean>();
		map.put("success", false);
		// 将对象转为json字符串
		String string = new ObjectMapper().writeValueAsString(map);
		response.setContentType("text/json;charset=utf-8");
		response.getWriter().write(string);
	}
}

整合ssm

RBAC数据库表


在这里插入图片描述
1、引入pom

org.mybatis>mybatis
org.mybatis>mybatis-spring	整合包
com.alibaba>druid	数据源
mysql>mysql-connector-java		驱动
org.springframework>spring-jdbc		使用spring的事务管理

2、整合mybatis

<context:component-scan base-package="com.lida.service"></context:component-scan>
	<context:property-placeholder location="classpath:jdbc.properties" />
	<!-- 连接池 -->
	<bean id="datasource" class="com.alibaba.druid.pool.DruidDataSource">
		<property name="url" value="${jdbc.url}"></property>
		<property name="driverClassName" value="${jdbc.driverClass}"></property>
		<property name="username" value="${jdbc.username}"></property>
		<property name="password" value="${jdbc.password}"></property>
		<!-- 最大线程数字 10个 -->
		<property name="maxActive" value="10"></property>
		<!-- 最长等待时间3秒 -->
		<property name="maxWait" value="3000"></property>
	</bean>

	<!-- mybatis整合spring -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="datasource"></property>
		<!-- 别名扫描 ,用于扫描写sql时的所要使用的实体 -->
		<property name="typeAliasesPackage" value="com.lida.entity"></property>
	</bean>
	<!-- mapper接口扫描 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.lida.mapper"></property>
	</bean>

	<!-- 事务相关 -->
	<bean
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 开启事务注解 -->
	<tx:annotation-driven />

3、编写MyUserDetails ,Permission Role

注意!!MyUserDetails 是要求实现UserDetails接口的,所有数据库的字段名应该与它所要求的一致

public class MyUserDetails implements UserDetails {
	private String username;
	private String password;
	private boolean enabled;
	private boolean accountNonExpired;
	private boolean accountNonLocked;
	private boolean credentialsNonExpired;
}
public class Role {
	private Integer id;
	private String roleName;
	private String roleDesc;
}
public class Permission {
	private Integer id;
	private String permName;
	private String permTag;	//这是权限的标识,
}

4、编写spring-security.xml

<security:http>
		<!-- 拦截 -->
		<security:intercept-url pattern="/prodect/index"
			access="permitAll()" />
		<security:intercept-url pattern="/userLoginPage"
			access="permitAll()" />
		<security:intercept-url pattern="/**"
			access="isFullyAuthenticated()" />

		<security:form-login login-page="/userLoginPage" />
	</security:http>

	<security:authentication-manager>
		<security:authentication-provider
			ref="myUserDetailsService">
			<!-- 使用加密算法对用户输入进行加密,然后再与数据库里的匹配-->
			<security:password-encoder ref="passwordEncoder"></security:password-encoder>
		</security:authentication-provider>
	</security:authentication-manager>

	<!-- 引用加密算法 -->
	<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></bean>
	<bean id="myUserDetailsService" class="com.lida.MyUserDetailsService"></bean>

5、编写MyUserDetailsService

public class MyUserDetailsService implements UserDetailsService {
	@Autowired
	UserMapper userMapper;
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		// 查询用户信息
		MyUserDetails myUserDetails = userMapper.findUserByUserName(username);

		// 查询用户权限
		List<Permission> permissions = userMapper.findPermissionByUserName(username);
		// 存放所有的权限
		List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
		// 构造满足条件的权限类
		for (Permission permission : permissions) {
			SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permission.getPermTag());
			authorities.add(authority);
		}
		myUserDetails.setAuthorities(authorities);
		return myUserDetails;
	}
}
加入图形验证码

处理流程

处理流程
在这里插入图片描述
1、定制过滤器:ImageCodeAuthenticationFilter

public class ImageCodeAuthenticationFilter extends OncePerRequestFilter{
	//异常处理器
	private AuthenticationFailureHandler authenticationFailureHandler;

	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		//判断当前请求是否是登陆请求
		if(request.getRequestURI().contains("/login")) {
			try {
				//校验验证码	正确的放在session里
				String key = (String) request.getSession().getAttribute("key");
				//获取用户输入的验证码
				String imageCode =request.getParameter("imageCode");
				if(StringUtils.isEmpty(imageCode.trim())) {
					//抛出自定义的异常
					throw new ImageCodeException("验证码必须输入");
				}
				if(!imageCode.trim().equals(key.trim())) {
					throw new ImageCodeException("验证码错误");
				}
			} catch (AuthenticationException e) {
				//将异常交给自定义的AuthenticationFailureHandler处理
				authenticationFailureHandler.onAuthenticationFailure(request,response,e);
				return ;
			}
		}
	}
	public void setAuthenticationFailureHandler(AuthenticationFailureHandler authenticationFailureHandler) {
		this.authenticationFailureHandler = authenticationFailureHandler;
	}
}

2、自定义异常类:ImageCodeException

public class ImageCodeException extends AuthenticationException {
	public ImageCodeException(String msg,Throwable T) {
		super(msg ,T);
	}
	public ImageCodeException(String msg) {
		super(msg);
	}
}

3、自定义失败处理类:MyAuthenticationFailureHandler

public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
	// 认证失败后的处理逻辑
	public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException)
			throws IOException, ServletException {
		// 返回json字符串给前端
		Map map = new HashMap<String, Boolean>();
		map.put("success", false);
		//将错误信息传回浏览器 
		map.put("message", authenticationException.getMessage());
		
		// 将对象转为json字符串
		String string = new ObjectMapper().writeValueAsString(map);
		response.setContentType("text/json;charset=utf-8");
		response.getWriter().write(string);
	}
}

4、spring-security.xml整合:

<!-- 引用自定义过滤器,并注入自定义的异常处理类类 -->
	<bean id="imageCodeAuthenticationFilter" class="com.lida.ImageCodeAuthenticationFilter">
		<property name="authenticationFailureHandler" ref="myAuthenticationFailureHandler"></property>
	</bean>
	<bean id="myAuthenticationFailureHandler" class="com.lida.MyAuthenticationFailureHandler"></bean>


<security:http>
		<!-- 使用自定义过滤器  并指定在form-login-filter过滤器之前-->
		<security:custom-filter ref="myAuthenticationFailureHandler" before="FORM_LOGIN_FILTER"/>
</security:http>
remember me

处理流程


在这里插入图片描述
1、前端登陆页面的“记住我” 的表单的名字是:remember-me 这是固定的

2、spring-security.xml添加

	<!-- 配置存储位置 -->
<bean id="jdbcTokenRepositoryImpl"
		class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl">
		<!-- 使用之前配置的druid数据源存储 -->
		<property name="dataSource" ref="datasource" />
		<!-- 程序启动的时候在数据库中自动建表 -->
		<property name="createTableOnStartup" value="true" />
</bean>


		<!-- 加上rememberme 功能 -->
		<!-- 设置存储有效时间 -->
		<security:remember-me token-repository-ref="jdbcTokenRepositoryImpl" token-validity-seconds="3600"/>		
spring security 标签库

1、引入pom

org.springframework.security>spring-security-taglibs

2、jsp中引入

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

<!-- 使用 -->
<security:authorize access="hasAuthority('ROLE_ADD_PRODECT')">
	当用户有权限ROLE_ADD_PRODECT时候才渲染我呀
</security:authorize>
随时随地的获取用户信息
//获取登陆的用户名
		UserDetails userDetails =(UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

整合spring boot

1、

@Configuration
@EnableWebSecurity	//启动过滤连
public class SecurityConfig extends WebSecurityConfigurerAdapter{
	//代替了<security:authentication-manager>
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.inMemoryAuthentication().withUser("user").password("password").authorities("PRODUCT_ADD","PRODUCT_DELETE");
	}
	//代替了<security:http>
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
			.antMatchers("/add").hasAnyAuthority("PRODUCT_ADD")
			.antMatchers("/login").permitAll()
			.antMatchers("/**")
			.fullyAuthenticated()
			.and()
			.formLogin().loginPage("/login")
			.and()
			.csrf().disable();
	}
}

2、

@Configuration
public class ErrorPageConfig {
	@Bean
	public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer() {
		return new EmbeddedServletContainerCustomizer() {
			//定义错误页面:指定当匹配到那个错误时,做什么请求处理
			public void customize(ConfigurableEmbeddedServlectContainer container) {
				container.addErrorPages(new ErrorPage(HttpStatus.FORBIDDEN,"/403"));
			}
		}
	}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值