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-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进行权限认证》进行查看
快速构建项目
喜欢这篇文章么,喜欢就加入我们一起讨论SpringBoot技术吧!
品茗IT交流群
网友评论