美文网首页javaWeb学习SpringBoot专题
SpringBoot入门建站全系列(十一)Spring-secu

SpringBoot入门建站全系列(十一)Spring-secu

作者: 逍遥天扬 | 来源:发表于2019-06-21 14:59 被阅读65次

    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

    一、配置

    本文假设你已经引入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交流群

    相关文章

      网友评论

        本文标题:SpringBoot入门建站全系列(十一)Spring-secu

        本文链接:https://www.haomeiwen.com/subject/pwiyqctx.html