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依赖


    org.mybatis.spring.boot
    mybatis-spring-boot-starter


    mysql
    mysql-connector-java


    org.apache.commons
    commons-dbcp2


    org.springframework.boot
    spring-boot-starter-security

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 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({
        ""})
    UserInfo findByUserName(@Param("userName") String userName);
    
    
}

六、过程中用到的实体

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

快速构建项目

Spring组件化构建

SpringBoot组件化构建

SpringCloud服务化构建

喜欢这篇文章么,喜欢就加入我们的Java学习圈(点击加入或下方扫码)一起讨论SpringBoot技术吧!

品茗IT交流群

你可能感兴趣的:(SpringBoot入门建站全系列(十一)Spring-security进行权限认证)