展开
拓展 关闭
订阅号推广码
GitHub
视频
公告栏 关闭

security单点登录案例

案例简介

  • 前端发送登录请求,登录成功后,将用户信息及该用户所拥有的权限保存到redis数据库中,同时生成token,将token放到cookie中返回给前端;之后前端每次向后端发送请求时,将token保存在请求头中发送给后端,后端接受到后与redis中的token进行比较,若一致则可以操作

  • 数据库设计

  • 需求功能

1. 登录认证
2. 创建角色,为角色分配菜单
3. 创建用户
4. 为用户分配角色权限

  • 所需技术
GateWay网关:对外暴露一个统一的端口,当访问该服务器端口时,网关会通过Nacos(注册中心)将(反向代理的方式)请求转发到自己的端口
Jwt:用于对数据加密处理成token
Redis
Swagger

  • 项目结构
acl_parent     父工程,在pom文件中定义依赖版本
 |
 |- common     子模块
 |    |- service_base     common模块中的子模块,如md5工具类
 |    |- spring_security     SpringSecurity配置
 |
 |- infrastructure     子模块
 |    |- api_gateway     网关配置
 |
 |- service     子模块
      |- service_acl     权限管理

  • 按以上结果创建项目,在acl_parent的pom中添加pom,同时可看到如下
    <modules>
        <module>common</module>
        <module>infrastructure</module>
        <module>service</module>
    </modules>
  • 在common、infrastructure、service子模块pom中添加如下,同时可看到子模块
<packaging>pom</packaging>
  • 在最底层的子模块中不需要添加pom
  • 导入所需的依赖

开发步骤

  • 公共类、security公共类、security业务类

  • 编写公共模块

  • security公共模块

  • security业务类编写

  • 启动mysql、redis、nacos,导入sql脚本

  • 编写UserDetailsServiceImpl

// security-service模块
import com.chnq.security.entity.User;
import com.chnq.security.service.PermissionService;
import com.chnq.security.service.UserService;
// common-security模块
import com.chnq.security.entity.SecurityUser;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
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 java.util.List;

@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserService userService;

    @Autowired
    private PermissionService permissionService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //根据用户名查询数据
        User user = userService.selectByUsername(username);
        //判断
        if(user == null) {
            throw new UsernameNotFoundException("用户不存在");
        }
        // 导入common-security模块中的实体对象
        com.chnq.security.entity.User curUser = new com.chnq.security.entity.User();
        BeanUtils.copyProperties(user,curUser);

        //根据用户查询用户权限列表
        List<String> permissionValueList = permissionService.selectPermissionValueByUserId(user.getId());
        SecurityUser securityUser = new SecurityUser();
        securityUser.setCurrentUserInfo(curUser);
        securityUser.setPermissionValueList(permissionValueList);
        return securityUser;
    }
}

  • 业务模块简介
RoleController  # 角色
PermissionController  # 菜单
UserController  # 用户
IndexController  # 登录成功后对象返回的对象交给security管理,从security中获取用户信息

  • 编写网关模块
  • pom
<?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">
    <parent>
        <artifactId>mysecurity</artifactId>
        <groupId>com.chnq.security</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>api-gateway</artifactId>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- 公共模块中的web starter依赖与gateway冲突 -->
<!--        <dependency>-->
<!--            <groupId>com.chnq.security</groupId>-->
<!--            <version>1.0-SNAPSHOT</version>-->
<!--            <artifactId>common-base</artifactId>-->
<!--        </dependency>-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>2.2.1.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-gateway -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
            <version>2.2.1.RELEASE</version>
        </dependency>
        <!--gson-->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
        </dependency>

        <!--服务调用-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>

</project>
  • yml
server:
  port: 8222
spring:
  application:
    name: service-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true # 服务发现能找到路由
      #路由规则 根据指定规则访问对应路径
      routes:
        - id: security-service
          predicates: Path=/*/acl/**
          uri: lb://security-service
    nacos:
      discovery:
        server-addr: 192.168.97.34:8848
  • 跨域配置类
package com.chen.security.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;

@Configuration
public class CorsConfig {

    @Bean
    public CorsWebFilter corsWebFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);

        return new CorsWebFilter(source);
    }
}

  • 配置网关报错
# 1. java.lang.IllegalStateException: Failed to introspect Class [org.springframework.cloud.gateway.config.GatewayAutoConfiguration$NettyConfiguration] from ClassLoader [jdk.internal.loader.ClassLoaders$AppClassLoader@7b1d7fff]

# 错误原因:springcloud的版本和springboot的版本对应不上
# 解决方案:将gateway版本改为与spring cloud一致
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
    <version>2.2.1.RELEASE</version>
</dependency>

# 2. 启动项目报错spring mvc found on classpath, which is incompatible with spring cloud 
# 错误原因:web starter依赖与gateway冲突
# 解决方案:查看父工程pom或导入的公共模块中包含web starter

业务逻辑

posted @ 2022-01-04 13:18  DogLeftover  阅读(55)  评论(0编辑  收藏  举报