SpringBoot+SpringSecurity+mysql实现认证与授权

13 篇文章 4 订阅
4 篇文章 4 订阅

SprinBoot 系列文章:

Spring Boot入门之Hello Spring Boot
SpringBoot 配置多个JdbcTemplate
SpringBoot 整合Mybatis
CAS统一登录认证(3): CAS 客户端接入实践
SpringBoot 整合Mail实现邮件发送
数据库连接池优化配置(druid,dbcp,c3p0)
SpringBoot+SpringSecurity+mysql实现认证与授

SpringBoot+Spring Security基于内存用户认证 
SpringBoot+WebSocket在线聊天室、消息推送 
SpringBoot+SpringData JPA操作Mysql数据库 
SpringBoot热部署值devtools配置
Spring Boot 资源文件属性配置 
Spring Boot Server等内容的配置
Spring Boot + FreeMarker模板 
SpringBoot+thymeleaf模板

SpringBoot + JDBC 连接MYSQL数据库
Zipkin分布式任务追踪 
SpringBoot应用部署到外置Tomcat 
Spring Boot + Swagger2 自动生成api接口文档 

SpringBoot整合Shiro安全框架          
SpringBoot+CAS Client 实现单点登录

SpringBoot 整合MyBatis-Plus  
SpringBoot + validation 接口参数校验
Springboot+Redis 实现API接口防刷限流
          
ShardingSphere-ShardingJdbc 数据分片(分库、分表)
ShardingSphere-ShardingJdbc 读写分离
ShardingSphere-ShardingJdbc 数据脱敏

            
springboot+sms 集成腾讯云短信平台
SpringBoot+RabbitMQ 实现消息队列
快速从零搭建一个SpringBoot Web项目
从零快速搭建一个SpringBoot Web项目
            
SpringBoot+ElasticSearch 实现全文检索
访问ElasticSearch的几种方式
SpringBoot + Activiti 工作流引擎(一、基本概念与环境搭建)
SpringBoot + Activiti 工作流引擎(二、流程&任务操作)
SpringBoot 定时任务 实现方式
            
SpringBoot + EhCache实现本地缓存
SpringBoot + Redis 实现分布式缓存 

一、Spring Security框架

1. 框架简介

        官方介绍:Spring Security是一个功能强大且可高度自定义的身份验证和访问控制框架。它是保护基于Spring的应用程序的事实标准。 Spring Security是一个专注于为Java应用程序提供身份验证和授权的框架。与所有Spring项目一样,Spring Security的真正强大之处在于它可以轻松扩展以满足自定义要求。

        Spring Security是一个为基于Spring的企业应用系统提供声明式的安全访问控制解决方式的安全框架(简单说是对访问权限进行控制),应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分。Spring Security的主要核心功能为 认证和授权,所有的架构也是基于这两个核心功能去实现的。

        用户认证: 验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。

        用户授权: 验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。

特征:

  • 对身份验证和授权的全面和可扩展的支持
  • 防止会话固定,点击劫持,跨站点请求伪造等攻击
  • Servlet API集成
  • 可选与Spring Web MVC集成

2. 框架原理

        想要对对Web资源进行保护,最好的办法莫过于Filter,要想对方法调用进行保护,最好的办法莫过于AOP。所以Spring Security在我们进行用户认证以及授予权限的时候,通过各种各样的拦截器来控制权限的访问,从而实现安全。

Spring Security 框架的主要过滤器(Filter) :

想要对对Web资源进行保护,最好的办法莫过于Filter,要想对方法调用进行保护,最好的办法莫过于AOP。所以Spring Security在我们进行用户认证以及授予权限的时候,通过各种各样的拦截器来控制权限的访问,从而实现安全。

Spring Security 框架的主要过滤器(Filter) : 

  • WebAsyncManagerIntegrationFilter 
  • SecurityContextPersistenceFilter 
  • HeaderWriterFilter 
  • CorsFilter 
  • LogoutFilter
  • RequestCacheAwareFilter
  • SecurityContextHolderAwareRequestFilter
  • AnonymousAuthenticationFilter
  • SessionManagementFilter
  • ExceptionTranslationFilter
  • FilterSecurityInterceptor
  • UsernamePasswordAuthenticationFilter
  • BasicAuthenticationFilter

  Spring Security框架的核心组件:

  • SecurityContextHolder:提供对SecurityContext的访问
  • SecurityContext:持有Authentication对象和其他可能需要的信息
  • AuthenticationManager:其中可以包含多个AuthenticationProvider
  • ProviderManager:AuthenticationManager接口的实现类
  • AuthenticationProvider:主要用来进行认证操作的类,调用其中的authenticate()方法去进行认证操作
  • Authentication:Spring Security方式的认证主体
  • GrantedAuthority:对认证主题的应用层面的授权,含当前用户的权限信息,通常使用角色表示
  • UserDetails:构建Authentication对象必须的信息,可以自定义,可能需要访问DB得到
  • UserDetailsService:通过username构建UserDetails对象,通过loadUserByUsername根据userName获取UserDetail对象 (可以在这里基于自身业务进行自定义的实现,如通过数据库、xml、缓存获取等)  

二、SpringBoot 整合Spring Security

1. 项目环境

(1)JDK版本:1.8

(2)Spring Boot:2.1.2.RELEASE

(3)Spring Security 5.1.3

(4)IntelliJ IDEA 2016.3.4

2.建库建表

建表语句如下,用户对应的密码已经使用md5加密。

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `Id` int(11) NOT NULL AUTO_INCREMENT,
  `userName` varchar(255) DEFAULT NULL COMMENT '姓名',
  `password` varchar(255) DEFAULT NULL COMMENT '密码',
  `roles` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`Id`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='用户表';

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'ouyang', 'bbd126f4856c57f68d4e30264da6a4e6', 'ROLE_ADMIN,ROLE_USER');
INSERT INTO `user` VALUES ('2', 'admin', 'bbd126f4856c57f68d4e30264da6a4e6', 'ROLE_ADMIN');
INSERT INTO `user` VALUES ('3', 'user', 'bbd126f4856c57f68d4e30264da6a4e6', 'ROLE_USER');

3.添加依赖并配置yml

依赖pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.oycbest</groupId>
    <artifactId>springsecuritytest</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    <name>springsecuritytest</name>
    <description>springsecurity 安全认证框架实战项目</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.8.1</version>
        </dependency>


        <!--Spring Boot热加载 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

        <!--Spring Security-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!--thymeleaf-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!--JDBC-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.29</version>
        </dependency>
        <!--spring-data-jpa-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

application.yml配置:

server:
  port: 8082

spring:
    datasource:
        url: jdbc:mysql://127.0.0.1:3306/springsecurity?autoReconnect=true&autoReconnectForPools=true&useUnicode=true&characterEncoding=utf8
        username: ouyangcheng
        password: 123456
        driver-class-name: com.mysql.jdbc.Driver
        druid:
            initialSize: 1
            minIdle: 1
            maxActive: 50
            maxWait: 6000
            timeBetweenEvictionRunsMillis: 6000
            minEvictableIdleTimeMillis: 30000
            testWhileIdle: true
            testOnBorrow: true
            testOnReturn: true
            validationQuery: SELECT 1 from dual
            connectionProperties: config.decrypt=false

4.创建spring security 的配置文件

package com.oycbest.config;

import com.oycbest.domain.User;
import com.oycbest.service.PasswordEncoder;
import com.oycbest.service.UserService;
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 org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.annotation.Resource;

/**
 * @Author: oyc
 * @Date: 2019/1/29 13:45
 * @Description:
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private UserService<User> userService;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService).passwordEncoder(new PasswordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //允许基于HttpServletRequest使用限制访问
        http.authorizeRequests()
                //不需要身份认证
                .antMatchers("/", "/home","/toLogin","/**/customer/**").permitAll()
                .antMatchers("/js/**", "/css/**", "/images/**", "/fronts/**", "/doc/**", "/toLogin").permitAll()
                .antMatchers("/user/**").hasAnyRole("USER")
                //.hasIpAddress()//读取配置权限配置
                .antMatchers("/**").access("hasRole('ADMIN')")
                .anyRequest().authenticated()
                //自定义登录界面
                .and().formLogin().loginPage("/toLogin").loginProcessingUrl("/login").failureUrl("/toLogin?error").permitAll()
                .and().logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                .and().exceptionHandling().accessDeniedPage("/toLogin?deny")
                .and().httpBasic()
                .and().sessionManagement().invalidSessionUrl("/toLogin")
                .and().csrf().disable();
    }
}

5.创建UserService实现了UserDetialsServer的类

        这个类主要是实现了loadUserByname方法, 然后我们可以在这个类中注入我们的service、repository或者mapper接口, 然后方法内部根据username获得该用户, 然后再获取这个用户的权限。通过用户名到数据库进行查询,如果没有查到这个用户,则登录失败留在原网页,如果查出这个用户,则把用户的账号密码和查出的用户拥有的所有权限,封装到security自己的User类中返回(得到的形式是这样的org.springframework.security.core.userdetails.User@c41325a7: Username: ouyang; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN,ROLE_USER),接下来security会把前台发过来的密码和查到的密码进行比较,看是否登录成功,失败停留在原网页,这一步框架自己解决,不需要我们来判断,只需要返回User即可。

        我这里直接注入UserRepository,使用UserRepository直接获取用户的信息和权限,对UserRepository有疑问可参考上节Spring Boot入门系列八(SpringBoot 整合SpringData JPA操作Mysql数据库): https://blog.csdn.net/u014553029/article/details/86662518

package com.oycbest.service;

import com.oycbest.domain.User;
import com.oycbest.repository.UserRepository;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: oyc
 * @Date: 2019/1/29 14:19
 * @Description: 用户服务类
 */
@Service
public class UserService<T extends User> implements UserDetailsService {

    @Resource
    private UserRepository<User> repository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        try {
            User user = repository.findByUserName(username);
            if (user == null) {
                throw new UsernameNotFoundException("用户名不存在");
            }
            //用户权限
            List<SimpleGrantedAuthority> authorities = new ArrayList<>();
            if (StringUtils.isNotBlank(user.getRoles())) {
                String[] roles = user.getRoles().split(",");
                for (String role : roles) {
                    if (StringUtils.isNotBlank(role)) {
                        authorities.add(new SimpleGrantedAuthority(role.trim()));
                    }
                }
            }
            return new org.springframework.security.core.userdetails.User(user.getUserName(), user.getPassword(), authorities);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

6.其他

使用到的login.html、MD5Util和PasswordEncoder,代码如下:

login.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
    <title>Spring Security Example </title>
</head>
<body>
<div th:if="${param.error}" style="color: red;">
    Invalid username and password.
</div>
<div th:if="${param.logout}" style="color: red;">
    You have been logged out.
</div>
<form th:action="@{/login}" method="post">
    <div><label> User Name : <input type="text" name="username"/> </label></div>
    <div><label> Password: <input type="password" name="password"/> </label></div>
    <div><input type="submit" value="submit"/> <input type="reset" value="reset"/></div>
</form>
<p>Click <a th:href="@{/home}">here</a> go to home page.</p>
</body>
</html>

MD5Util.java

package com.oycbest.util;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * @Author: oyc
 * @Date: 2018/12/3 11:11
 * @Description: MD5加密工具
 */
public class MD5Util {

    public static final int time = 5;

    public static final String SALT = "springsecurity";

    /**
     * 密码加密方法
     *
     * @param password
     * @return
     */
    public static String encode(String password) {
        MessageDigest digest;
        try {
            digest = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException("MD5 algorithm not available.  Fatal (should be in the JDK).");
        }
        try {
            for (int i = 0; i < time; i++) {
                byte[] bytes = digest.digest((password + SALT).getBytes("UTF-8"));
                password = String.format("%032x", new BigInteger(1, bytes));
            }
            return password;
        } catch (UnsupportedEncodingException e) {
            throw new IllegalStateException("UTF-8 encoding not available.  Fatal (should be in the JDK).");
        }
    }

    public static void main(String[] args) {
        System.out.println(MD5Util.encode("123456"));
    }
}

PasswordEncoder.java

package com.oycbest.service;

import com.oycbest.util.MD5Util;

/**
 * @Author: oyc
 * @Date: 2018/12/3 10:29
 * @Description: 密码加密类
 */
public class PasswordEncoder implements org.springframework.security.crypto.password.PasswordEncoder {

    @Override
    public String encode(CharSequence rawPassword) {
        return MD5Util.encode((String) rawPassword);
    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {//user Details Service验证
        return encodedPassword.equals(MD5Util.encode((String) rawPassword));
    }

}

三、测试

        先使用用户ouyang登录,因为ouayng拥有所有权限,所以可以访问admin和user;当使用admin用户登录的时候,可以正常访问到admin,但是访问user路径时候,就被拦截的,因为admin用户不具备访问user路径的权限。

 

UserService中的loadUserByUsername在认证过程获取数据如下:

源码地址:https://github.com/oycyqr/SpringSecurity

  • 13
    点赞
  • 81
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Spring Security是一个强大的安全框架,它是基于Spring框架的安全解决方案。它提供了一种全面的安全服务,可以在Web请求级别和方法级别进行安全控制。Spring Security提供了身份验证、授权和攻击保护等方面的支持,同时也支持灵活的安全配置和扩展。 关于如何结合SpringBootMySQLSpringSecurity和Vue编写一套完整的权限框架,可以按照以下步骤进行: 1、在SpringBoot中集成Spring SecurityMySQL:通过添加相应的依赖,配置数据源和Spring Security配置文件,以及实现UserDetailsService接口和PasswordEncoder接口对用户进行认证授权。 2、编写Vue前端页面:使用Vue.js可以快速地构建一个前端单页应用,通过Vue Router和axios实现页面跳转和数据交互。 3、实现用户、角色和权限管理功能:在后端,实现用户、角色和权限的CRUD操作,同时结合Spring Security实现用户与URL的权限控制;在前端,通过Vue组件和API调用,实现相应的页面展示和操作。 4、实现Spring Security的自定义认证授权:可以通过实现AuthenticationProvider接口和AccessDecisionVoter接口,对用户自定义认证授权进行处理。 5、通过JWT实现无状态认证:使用JwtTokenStore和JwtTokenEnhancer等相关组件,实现无状态认证授权,提高Web应用的性能和扩展性。 以上就是一个简单的SpringBoot+MySQL+Spring Security+Vue权限框架实现的基本思路,可以根据实际项目需求做出适当的调整和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值