SpringBoot入门建站全系列(十一)Spring-security进行权限认证

SpringBoot入门建站全系列(十一)Spring-security进行权限认证

Spring 是一个非常流行和成功的 Java 应用开发框架。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分。用户认证指的是验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。

Spring-security其实就是用filter,多请求的路径进行过滤。

如果是基于Session,那么Spring-security会对cookie里的sessionid进行解析,找到服务器存储的sesion信息,然后判断当前用户是否符合请求的要求。

如果是token,则是解析出token,然后将当前请求加入到Spring-security管理的权限信息中去。

项目地址:
品茗IT-同步发布

品茗IT 提供在线支持:

一键快速构建Spring项目工具

一键快速构建SpringBoot项目工具

一键快速构建SpringCloud项目工具

一站式Springboot项目生成

Mysql一键生成Mybatis注解Mapper

如果大家正在寻找一个java的学习环境,或者在开发中遇到困难,可以加入我们的java学习圈,点击即可加入,共同学习,节约学习时间,减少很多在学习中遇到的难题。

一、配置

本文假设你已经引入spring-boot-starter-web。已经是个SpringBoot项目了,如果不会搭建,可以打开这篇文章看一看《SpringBoot入门建站全系列(一)项目建立》

1.1 Maven依赖
<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
	<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-dbcp2</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>

Spring-security一般需要从数据库中查询用户信息的,所以这里还是要把mybatis引入,以查询用户信息使用。

1.2 配置文件

application.properties 中需要添加下面的配置:

spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource
spring.datasource.dbcp2.max-wait-millis=60000
spring.datasource.dbcp2.min-idle=20
spring.datasource.dbcp2.initial-size=2
spring.datasource.dbcp2.validation-query=SELECT 1
spring.datasource.dbcp2.connection-properties=characterEncoding=utf8
spring.datasource.dbcp2.validation-query=SELECT 1
spring.datasource.dbcp2.test-while-idle=true
spring.datasource.dbcp2.test-on-borrow=true
spring.datasource.dbcp2.test-on-return=false

spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/boot?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
spring.datasource.username=cff
spring.datasource.password=123456

mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

这里的配置主要就是数据库连接和数据源、mybatis的配置。因为要连接数据库。

二、安全控制核心

Spring Security的核心配置就是继承WebSecurityConfigurerAdapter并注解@EnableWebSecurity的配置。

这个配置指明了用户名密码的处理方式、请求路径的开合、登录登出控制等和安全相关的配置。

ApiSecurityConfig:

package com.cff.springbootwork.security.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

import com.cff.springbootwork.security.handler.AjaxAuthFailHandler;
import com.cff.springbootwork.security.handler.AjaxAuthSuccessHandler;
import com.cff.springbootwork.security.handler.AjaxLogoutSuccessHandler;
import com.cff.springbootwork.security.handler.UnauthorizedEntryPoint;
import com.cff.springbootwork.security.provider.SimpleAuthenticationProvider;

@EnableWebSecurity
public class ApiSecurityConfig {

	@Configuration                                                   
	public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
		@Autowired
		private SimpleAuthenticationProvider simpleAuthenticationProvider;
		
		@Autowired
		public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
			auth.authenticationProvider(simpleAuthenticationProvider);
		}

		@Override
		public void configure(HttpSecurity http) throws Exception {
			http.csrf().disable().exceptionHandling()
					.authenticationEntryPoint(new UnauthorizedEntryPoint())
					.and().headers()
					.frameOptions().disable().and().authorizeRequests()
					.antMatchers("/login").permitAll()
					.antMatchers("/login.html").permitAll()
					.antMatchers("/error.html").permitAll()
					.antMatchers("/img/**").permitAll()
					.antMatchers("/css/**").permitAll()
					.antMatchers("/pub/**").permitAll()
					.anyRequest().authenticated()
					.and()
					.formLogin()
					.usernameParameter("userName").passwordParameter("password")
					.loginProcessingUrl("/login")
					.successHandler(new AjaxAuthSuccessHandler())
					.failureHandler(new AjaxAuthFailHandler())
					.and()
					.logout()
					.logoutUrl("/logout").logoutSuccessHandler(new AjaxLogoutSuccessHandler());
		}
	}
}

这里:

  • SimpleAuthenticationProvider :用户名密码校验过程的处理方式。

  • UnauthorizedEntryPoint:未授权的统一处理方式。

  • successHandler、failureHandler、logoutSuccessHandler顾名思义,就是响应处理逻辑,如果不打算单独处理,只做跳转,有响应的successForwardUrl、failureForwardUrl、logoutSuccessUrl等。

三、用户名密码校验

SimpleAuthenticationProvider实现了AuthenticationProvider 接口的authenticate方法,提供用户名密码的校验,校验成功后,生成UsernamePasswordAuthenticationToken。

SimpleAuthenticationProvider:

package com.cff.springbootwork.security.provider;

import java.util.Collection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.stereotype.Component;

import com.cff.springbootwork.mybatis.domain.UserInfo;
import com.cff.springbootwork.mybatis.service.UserInfoService;

@Component
public class SimpleAuthenticationProvider implements AuthenticationProvider {
	@Autowired
	private UserInfoService userInfoService;

	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {

		String userName = authentication.getPrincipal().toString();
		UserInfo user = userInfoService.getUserInfoByUserName(userName);

		if (user == null) {
			throw new BadCredentialsException("查无此用户");
		}
		if (user.getPasswd() != null && user.getPasswd().equals(authentication.getCredentials())) {
			Collection<? extends GrantedAuthority> authorities = AuthorityUtils.NO_AUTHORITIES;

			return new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPasswd(), authorities);
		} else {
			throw new BadCredentialsException("用户名或密码错误。");
		}
	}

	@Override
	public boolean supports(Class<?> arg0) {
		return true;
	}

}


四、安全处理的一些handler

UnauthorizedEntryPoint:

package com.cff.springbootwork.security.handler;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;

import com.cff.springbootwork.security.model.ResultCode;
import com.cff.springbootwork.security.model.ResultModel;
import com.fasterxml.jackson.databind.ObjectMapper;

public class UnauthorizedEntryPoint implements AuthenticationEntryPoint {
	@Override
	public void commence(HttpServletRequest request, HttpServletResponse response,
			AuthenticationException authException) throws IOException, ServletException {
		ResultModel rm = new ResultModel(ResultCode.CODE_40004);
		ObjectMapper mapper = new ObjectMapper();
		response.setStatus(HttpStatus.OK.value());
		response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
		mapper.writeValue(response.getWriter(), rm);
	}
}

AjaxAuthSuccessHandler:

package com.cff.springbootwork.security.handler;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;

import com.cff.springbootwork.security.model.ResultCode;
import com.cff.springbootwork.security.model.ResultModel;
import com.fasterxml.jackson.databind.ObjectMapper;

public class AjaxAuthSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
	protected final Log logger = LogFactory.getLog(this.getClass());

	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws IOException, ServletException {
		ResultModel rm = new ResultModel(ResultCode.CODE_00000);
		ObjectMapper mapper = new ObjectMapper();
		response.setStatus(HttpStatus.OK.value());
		response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
		mapper.writeValue(response.getWriter(), rm);
	}

}

AjaxAuthFailHandler:

package com.cff.springbootwork.security.handler;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;

import com.cff.springbootwork.security.model.ResultCode;
import com.cff.springbootwork.security.model.ResultModel;
import com.fasterxml.jackson.databind.ObjectMapper;

public class AjaxAuthFailHandler extends SimpleUrlAuthenticationFailureHandler {
	@Override
	public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
			AuthenticationException exception) throws IOException, ServletException {
		ResultModel rm = new ResultModel(ResultCode.CODE_00014.getCode(), exception.getMessage());
		ObjectMapper mapper = new ObjectMapper();
		response.setStatus(HttpStatus.OK.value());
		response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
		mapper.writeValue(response.getWriter(), rm);
	}

}

AjaxLogoutSuccessHandler:

package com.cff.springbootwork.security.handler;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;

import com.cff.springbootwork.security.model.ResultCode;
import com.cff.springbootwork.security.model.ResultModel;
import com.fasterxml.jackson.databind.ObjectMapper;

public class AjaxLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
	public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
			throws IOException, ServletException {
		ResultModel rm = new ResultModel(ResultCode.CODE_00000);
		ObjectMapper mapper = new ObjectMapper();
		response.setStatus(HttpStatus.OK.value());
		response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
		mapper.writeValue(response.getWriter(), rm);

	}

}

五、用户信息查询

UserInfoService:

package com.cff.springbootwork.mybatis.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.cff.springbootwork.mybatis.dao.UserInfoDao;
import com.cff.springbootwork.mybatis.domain.UserInfo;

@Service
public class UserInfoService {
	@Autowired
	UserInfoDao userInfoDao;
	public UserInfo getUserInfoByUserName(String userName){
		return userInfoDao.findByUserName(userName);
	}
}

UserInfoDao:

package com.cff.springbootwork.mybatis.dao;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import com.cff.springbootwork.mybatis.domain.UserInfo;

@Mapper
public interface UserInfoDao {
	@Select({
		"<script>",
	        "SELECT ",
	        "user_name as userName,passwd,name,mobile,valid, user_type as userType",
	        "FROM user_info",
	        "WHERE user_name = #{userName,jdbcType=VARCHAR}",
	   "</script>"})
	UserInfo findByUserName(@Param("userName") String userName);
	
	
}

六、过程中用到的实体

详细完整的实体,可以访问品茗IT-博客《SpringBoot入门建站全系列(十一)Spring-security进行权限认证》进行查看

快速构建项目

Spring组件化构建

SpringBoot组件化构建

SpringCloud服务化构建

喜欢这篇文章么,喜欢就加入我们一起讨论SpringBoot技术吧!
品茗IT交流群

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值