https://blog.csdn.net/qq_52495761/article/details/138763893

csdn推荐

1、什么Spring Security?

Spring Security 是一种强大的框架,它在 Spring 生态系统中扮演着保护应用安全的关键角色。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。

2、认证 和 授权 1.什么是认证?

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

通俗点说就是系统认为用户是否能登录

在 Spring Security 中,认证是通过AuthenticationManager接口处理的,它通常使用一系列的AuthenticationProvider来验证用户身份。

2.什么是授权?

验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。

比如拿文件来说,有的用户只能进行读取,而有的用户可以进行修改。

通俗点讲就是系统判断用户是否有权限去做某些事情。

3、为什么Spring Security (对比) 特征Spring SecurityApache Shiro

设计哲学

集成于 Spring 框架,重点关注企业级安全需求。

独立的安全框架,设计简单,易于集成和使用。

主要优点

和 Spring 无缝整合,全面的权限控制,适应 Web 开发。新版本可脱离 Web 环境使用。

轻量级,性能优异,通用性强,不局限于 Web 环境。

局限性

旧版本依赖 Web 环境,重量级。

在 Web 环境下特定需求可能需手动编码。

认证支持

支持表单登录、LDAP、数据库认证、OAuth等。

支持多种认证策略,包括基于角色的访问控制和简单的身份验证。

授权支持

支持基于角色和表达式的访问控制。

提供静态和动态权限分配,支持角色基础的授权。

会话管理

依赖外部容器或Spring框架的会话管理。

内建会话管理,适合于非Web环境下的应用。

扩展性和定制

高度可定制和可扩展,适应复杂安全需求。

提供简单直接的扩展机制,易于快速部署和定制。

使用场景

适合大型企业级应用,尤其是基于Spring的应用。

适合不依赖Spring或需简单安全框架的应用。

常见技术栈

Spring Boot/Spring Cloud + Spring Security

SSM + Shiro

4、入门案例 1、新建SpringBoot工程securitydemo1(2.2.1.RELEASE)

2、POM


    org.springframework.boot
    spring-boot-starter-web


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

3、新建控制层

@RestController
public class TestController {
@GetMapping("/hello")
    public String test() {
    return "hello World";
    }
}

4、启动并访问localhost:8080/help进入如下验证页面

默认用户名user,密码为如下默认密码

5、基本原理 1. 认证(Authentication)

认证是过程中第一步,目的是确认一个用户的身份。用户在登录时提供凭据(通常是用户名和密码),Spring Security 通过配置的认证机制来验证这些凭据是否与系统中的相匹配。这个过程通常涉及以下几个组件:

2. 授权(Authorization)

一旦用户通过认证,下一步是确定他们是否有权执行特定的操作。授权可以在访问控制列表、角色基于的控制或更细粒度的权限控制级别上进行。

3. 安全过滤器链(Security Filter Chain)

Spring Security 使用一系列的过滤器来应用上述的认证和授权。这些过滤器在应用服务器处理请求的过程中工作,确保所有的HTTP请求都经过严格的安全检查。

4.过滤器链的加载过程

定义 FilterChainProxy:

配置 SecurityFilterChain:

过滤器的初始化:

Servlet 容器集成:

过滤器执行:

自定义和扩展:

6、接口 1.认证相关接口

AuthenticationManager

AuthenticationProvider

UserDetailsService

当什么也没有配置的时候,账号和密码是由 Spring Security 定义生成的。而在实际项目中账号和密码都是从数据库中查询出来的。 所以我们要通过自定义逻辑控制认证逻辑。如果需要自定义逻辑时,只需要实现 UserDetailsService 接口即可。

PasswordEncoder

2.授权相关接口

AccessDecisionManager

GrantedAuthority

3.过滤器相关接口和类

FilterChainProxy

安全过滤器

7、web权限方案 1、用户认证

设置登录的用户名和密码

1、配置文件方式

spring:
  security:
    user:
      name: zNuyoah
      password: zNuyoah

2、配置类方式

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String passwd = bCryptPasswordEncoder.encode("zNuyoah");
        auth.inMemoryAuthentication().withUser("zNuyoah").password(passwd).roles("admin");
    }
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

3、自定义编写实现类方式(常用)


@Service
public class MyUserDetailService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
    
    	// 赋予当前用户权限
        List auths = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
		
		// 这里的密码可以通过注入 mapper层 从数据库中查找
        return new User(
                "zNuyoah",
                new BCryptPasswordEncoder().encode("zNuyoah"),
                auths);
    }
}


@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyUserDetailsService myUserDetailsService;
	@Bean
    public PasswordEncoder password() {
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(password());
    } 
}

2、整合MybatisPlus 1、POM、YML



    com.baomidou
    mybatis-plus-boot-starter
    3.0.5


    mysql
    mysql-connector-java


    org.projectlombok
    lombok

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/security?serverTimezone=GMT%2B8
    username: root
    password: root

2、创建数据库 security

create table users (
	id bigint primary key auto_increment,
	username varchar(20) unique not null,
	password varchar(100)
);
insert into users values(1,'zNuyoah','zNuyoah');

3、实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Users {
    private Integer id;
    private String username;
    private String password;
}

4、数据交互层

public interface UserMapper extends BaseMapper {
}

5、业务层

@Service
public class MyUserDetailService implements UserDetailsService {
    @Autowired
    UserMapper userMapper;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("username", username);
        Users users = userMapper.selectOne(wrapper);
        if (users == null) {
            throw new UsernameNotFoundException("用户名不存在!");
        }
		
		// 授予权限(后面有用)
        List auths = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
        return new User(
                users.getUsername(),
                new BCryptPasswordEncoder().encode(users.getPassword()),
                auths);
    }
}

6、配置类

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyUserDetailsService myUserDetailsService;
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(password());
    }
    @Bean
    public PasswordEncoder password() {
        return new BCryptPasswordEncoder();
    }
}

7、控制层

@RestController
public class TestController {
    @GetMapping("/hello")
    public String test() {
        return "hello World";
    }
}

8、启动类


@MapperScan("com.zNuyoah.mapper")
@SpringBootApplication
public class SecurityDemo1Application {
    public static void main(String[] args) {
        SpringApplication.run(SecurityDemo1Application.class, args);
    }
}

3、自定义用户登录页面 1、配置类配置

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    MyUserDetailService myUserDetailService;
    @Bean
    public PasswordEncoder password() {
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailService).passwordEncoder(password());
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 自定义登录页面
        http.formLogin()
                .loginPage("/login.html")           // 自定义页面设置
                .loginProcessingUrl("/login") 		// 登录表单提交路径
                .defaultSuccessUrl("/index").permitAll() // 登录成功后跳转到
       	
       	// 权限认证
        http.authorizeRequests()
                .antMatchers("/", "/hello").permitAll() // 设置忽略的路径
                .anyRequest().authenticated()       // 设置所有路径都需认证(不包括忽略的路径)
                
        // 关闭csrf保护功能        
		http.csrf().disable();
    }
}

2、resource/static/login.html




    
    Title



    用户名:
密码:

3、控制层

@RestController
public class TestController {
    @GetMapping("/hello")
    public String test() {
        return "hello World";
    }
    @GetMapping("/index")
    public String index() {
        return "hello index";
    }
}

4、测试

1、/hello 可以直接访问

2、可以配置自定义登录页面

3、登录成功跳转到 /index

4、用户授权 1、hasAuthority 方法

如果当前的主体具有指定的权限,则返回 true,否则返回 false

配置类

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	@Override
	protected void configure(HttpSecurity http) throws Exception {
	    // 自定义登录页面
	    http.formLogin()
	            .loginPage("/login.html")          // 自定义页面设置
	            .loginProcessingUrl("/login")	   // 登录访问路径
	            .defaultSuccessUrl("/index").permitAll() // 登录成功后跳转到
	         
	    // 权限认证
	    http.authorizeRequests()
	            .antMatchers("/", "/hello", "/login").permitAll() // 设置忽略的路径
	            
	        $   .antMatchers("/index").hasAuthority("admin") // 当前登录用户只有具有admin权限才能访问
	            
	            .anyRequest().authenticated()      // 设置所有路径都需认证(不包括忽略的路径)
	            
	    // 关闭csrf保护功能        
		http.csrf().disable();
	}
}

当前登录用户只有具有admin权限才能访问

.antMatchers("/index").hasAuthority("admin")

接口

@Service
public class MyUserDetailService implements UserDetailsService {
    @Autowired
    UserMapper userMapper;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("username", username);
        Users users = userMapper.selectOne(wrapper);
        if (users == null) {
            throw new UsernameNotFoundException("用户名不存在!");
        }
		
		// 授予admin权限
    $   List auths = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
        return new User(
                users.getUsername(),
                new BCryptPasswordEncoder().encode(users.getPassword()),
                auths);
    }
}

授予admin权限

List auths = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");

若当前登录用户无对应权限,返回 403状态码

2、hasAnyAuthority 方法

如果当前的主体有任何提供的角色(给定的作为一个逗号分隔的字符串列表)的话,返回true

@Override
protected void configure(HttpSecurity http) throws Exception {
    // 自定义登录页面
    http.formLogin()
            .loginPage("/login.html")           // 自定义页面设置
            .loginProcessingUrl("/login") 		// 登录访问路径
            .defaultSuccessUrl("/index").permitAll() // 登录成功后跳转到
            
    http.authorizeRequests()
            .antMatchers("/", "/hello", "/login").permitAll() // 设置忽略的路径
            //.antMatchers("/index").hasAuthority("admin")  // 当前登录用户只有具有admin权限才能访问
        $   .antMatchers("/index").hasAnyAuthority("admin", "root") // 有其中一个权限就能访问
        
            .anyRequest().authenticated()      // 设置所有路径都需认证(不包括忽略的路径)
    
    http.csrf().disable();
}

3、hasRole 方法

如果当前主体具有指定的角色,则返回 true

源码

private static String hasRole(String role) {
    Assert.notNull(role, "role cannot be null");
    if (role.startsWith("ROLE_")) {
        throw new IllegalArgumentException("role should not start with 'ROLE_' since it is automatically inserted. Got '" + role + "'");
    } else {
        return "hasRole('ROLE_" + role + "')";
    }
}    

源码显示拼接用户名时为 ROLE_xxx

return "hasRole('ROLE_" + role + "')";

配置类添加角色授权

@Override
protected void configure(HttpSecurity http) throws Exception {
    // 自定义登录页面
    http.formLogin()
            .loginPage("/login.html")          // 自定义页面设置
            .loginProcessingUrl("/login") // 登录访问路径
            .defaultSuccessUrl("/index").permitAll() // 登录成功后跳转到
            
    http.authorizeRequests()
            .antMatchers("/", "/hello", "/login").permitAll() // 设置忽略的路径
            
       $    .antMatchers("/index").hasRole("admin") 
            
            .anyRequest().authenticated()      // 设置所有路径都需认证(不包括忽略的路径)
            
    http.csrf().disable();
}

此时接口方法授权限必须为

List auths = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_admin");

4、hasAnyRole

表示用户具备任何一个条件都可以访问

@Override
protected void configure(HttpSecurity http) throws Exception {
    // 自定义登录页面
    http.formLogin()
            .loginPage("/login.html")          // 自定义页面设置
            .loginProcessingUrl("/login") // 登录访问路径
            .defaultSuccessUrl("/index").permitAll() // 登录成功后跳转到
            
    http.authorizeRequests()
            .antMatchers("/", "/hello", "/login").permitAll() // 设置忽略的路径
            
     $      .antMatchers("/index").hasAnyRole("admin", "root") 
            
            .anyRequest().authenticated()      // 设置所有路径都需认证(不包括忽略的路径)
            
    http.csrf().disable();
}

5、自定义403页面 1、新建页面 /static/unauth.html


抱歉,你没有权限访问

2、配置类

@Override
protected void configure(HttpSecurity http) throws Exception {
    // 配置没有权限访问跳转自定义页面
    http.exceptionHandling().accessDeniedPage("/unauth.html");

@Override
protected void configure(HttpSecurity http) throws Exception {
    // 配置没有权限访问跳转自定义页面
    http.exceptionHandling().accessDeniedPage("/unauth.html");
    // 自定义登录页面
    http.formLogin()
            .loginPage("/login.html")           // 自定义页面设置
            .loginProcessingUrl("/login") 		// 登录访问路径
            .defaultSuccessUrl("/index").permitAll() // 登录成功后跳转到
            
    http.authorizeRequests()
            .antMatchers("/", "/hello", "/login").permitAll() // 设置忽略的路径
            .antMatchers("/index").hasAuthority("admin")
            .anyRequest().authenticated()      // 设置所有路径都需认证(不包括忽略的路径)
            
    http.csrf().disable();
}

3、授权

6、注解使用 1、@Secured:判断是否具有角色,另外需要注意的是这里匹配的字符串需要添加前缀 ROLE_

主启动类开启注解功能:@EnableGlobalMethodSecurity(securedEnabled=true)

控制层

@GetMapping("/update")
@Secured({"ROLE_sale", "ROLE_xxx"})
public String update() {
    return "hello update";
}

List auths = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_sale");

2、@PreAuthorize:注解适合进入方法前的权限验证, @PreAuthorize 可以将登录用户的

roles/permissions 参数传到方法中

主启动类开启注解功能:@EnableGlobalMethodSecurity(prePostEnabled = true)

@GetMapping("/update")
@PreAuthorize("hasAnyAuthority('admin')")
public String update() {
    return "hello update";
}

List auths = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");

3、@PostAuthorize:在方法执行后再进行权限验证,适合验证带有返回值的权限

主启动类开启注解功能:@EnableGlobalMethodSecurity(prePostEnabled = true)

@GetMapping("/update")
@PostAuthorize("hasAnyAuthority('xxx')")
public String update() {
    System.out.println("@@@@@@@@@@@@@@@@@@@@");
    return "hello update";
}

虽然无法访问页面,但是控制台输出了业务逻辑

4、@PostFilter:权限验证之后对返回值进行过滤


@GetMapping("/getAll")
@PreAuthorize("hasAnyAuthority('admin')")
@PostFilter("filterObject.username == 'zNuyoah'")
public List getAll() {
    ArrayList list = new ArrayList();
    list.add(new Users(1, "zNuyoah", "123"));
    list.add(new Users(2, "z_Nuyoah", "123"));
    
    System.out.println(list);
    
    return list;
}

5、@PreFilter:进入控制器之前对数据进行过滤

@GetMapping("/getAll")
@PreAuthorize("hasAnyAuthority('admin')")
@PreFilter("filterObject.username == 'laptoy'")
public List getAll(@RequestBody List list) {
    list.forEach(l -> {
        System.out.println(l.getUsername());
    });
    return list;
}

先登陆后使用PostMan进行测试

7、用户注销

1、login.html



    用户名:
密码:

2、success.html


登录成功

登出

3、配置类

@Override
protected void configure(HttpSecurity http) throws Exception {
    // 登出
    http.logout().logoutUrl("/logout").logoutSuccessUrl("/login.html").permitAll();
    // 自定义登录页面
    http.formLogin()
            .loginPage("/login.html")           // 自定义页面设置
            .loginProcessingUrl("/login")       // 登录访问路径
            .defaultSuccessUrl("/success.html").permitAll() // 登录成功后跳转到
            
    http.authorizeRequests()
            .antMatchers("/", "/login").permitAll() // 设置忽略的路径
            .anyRequest().authenticated()      // 设置所有路径都需认证(不包括忽略的路径)
            
    http.csrf().disable();
}

4、控制层

@RestController
public class TestController {
    @GetMapping("/index")
    public String index() {
        return "hello index";
    }
}

5、测试

1.访问 localhost:8080/login.html 登录成功后 点击 登出

2.访问 /index 需要重新进行登录验证

8、记住我功能 1、实现原理

2、认证及存放 Token 过程

代码实现

1、建表

CREATE TABLE `persistent_logins` (
	 `username` varchar(64) NOT NULL,
	 `series` varchar(64) NOT NULL,
	 `token` varchar(64) NOT NULL,
	 `last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE 
	  CURRENT_TIMESTAMP,
	  PRIMARY KEY (`series`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2、配置类 注入数据源,配置操作数据库对象

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	...
	
	// 注入数据源
	@Autowired
	private DataSource dataSource;
	// 配置对象
	@Bean
	public PersistentTokenRepository persistentTokenRepository() {
	    JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
	    jdbcTokenRepository.setDataSource(dataSource);
	    return jdbcTokenRepository;
	}
	
	...
}

3、配置类配置自动登录

protected void configure(HttpSecurity http) throws Exception {
	http.formLogin()
		.and().rememberMe().tokenRepository(persistentTokenRepository())
		.tokenValiditySeconds(60) // 设置有效时长 秒
		.userDetailsService(userDetailsService())
}

4、login.html


    用户名:
密码:
记住我:
在这里插入代码片

配置类全部代码展示

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyUserDetailService myUserDetailService;
    // 注入数据源
    @Autowired
    private DataSource dataSource;
    // 配置对象
    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        return jdbcTokenRepository;
    }
    @Bean
    public PasswordEncoder password() {
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailService).passwordEncoder(password());
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 登出
        http.logout().logoutUrl("/logout").logoutSuccessUrl("/login.html").permitAll();
        // 配置没有权限访问跳转自定义页面
        http.exceptionHandling().accessDeniedPage("/unauth.html");
        // 自定义登录页面
        http.formLogin()
                .loginPage("/login.html")                        // 自定义页面设置
                .loginProcessingUrl("/login")                    // 登录访问路径
                .defaultSuccessUrl("/success.html").permitAll(); // 登录成功后跳转到
        // 权限认证
        http.authorizeRequests()
                .antMatchers("/", "/hello", "/login").permitAll() // 设置忽略的路径
                .anyRequest().authenticated();       // 设置所有路径都需认证(不包括忽略的路径)
        // 记住我
        http.rememberMe().tokenRepository(persistentTokenRepository())
                .tokenValiditySeconds(60) // 设置有效时长 秒
                .userDetailsService(userDetailsService());
        // 关闭csrf保护功能
        http.csrf().disable();
    }
}

9、CSRF

跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session

riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的 Web 应用程序上执行非

本意的操作的攻击方法。跟跨网站脚本(XSS)相比,XSS利用的是用户对指定网站的信任,

CSRF 利用的是网站对用户网页浏览器的信任。

跨站请求攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾

经认证过的网站并运行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏

览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去运行。这利用了 web 中用户身

份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是

用户自愿发出的。

从 Spring Security 4.0 开始,默认情况下会启用 CSRF 保护,以防止 CSRF 攻击应用程序,

Spring Security CSRF 会针对 PATCH,POST,PUT 和 DELETE 方法进行防护。

1、登录页面添加隐藏域

2、配置类开启CSRF

// http.csrf().disable();

8、微服务权限方案 1、认证授权过程分析

如果系统的模块众多,每个模块都需要进行授权与认证,所以我们选择基于token 的形式进行授权

与认证

1、用户根据用户名密码认证成功,然后获取当前用户角色的一系列权限值

2、以 用户名为 key,权限列表为 value 的形式存入 redis 缓存中

3、根据用户名相关信息 生成 token返回

4、浏览器将 token记录到 cookie 中,每次调用 api 接口都默认将 token 携带 到 header 请求头中

5、Spring-security 解析 header 头获取 token 信息,解析 token 获取当前 用户名,根据用户

名就可以从 redis 中获取权限列表,

6、这样 Spring-security 就能够判断当前 请求是否有权限访问

2、数据模型

执行资料里的 SQL脚本

3、搭建项目工程

1、新建Springboot父工程 acl_parent (2.2.1.RELEASE)

●删除 src目录

●POM添加

pom



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.2.1.RELEASE
         
    
    com.laptoy
    acl_parent
    0.0.1-SNAPSHOT
    pom
    acl_parent
    acl_parent
    
        common
        infrastructure
        service
    
    
        1.8
        3.0.5
        2.0
        2.7.0
        0.7.0
        1.2.28
        2.8.2
        20170516
        0.2.2.RELEASE
    
    
        
            
            
                org.springframework.cloud
                spring-cloud-dependencies
                Hoxton.RELEASE
                pom
                import
            
            
                org.springframework.cloud
                spring-cloud-alibaba-dependencies
                ${cloud-alibaba.version}
                pom
                import
            
            
            
                com.baomidou
                mybatis-plus-boot-starter
                ${mybatis-plus.version}
            
            
            
                org.apache.velocity
                velocity-engine-core
                ${velocity.version}
            
            
                com.google.code.gson
                gson
                ${gson.version}
            
            
            
                io.springfox
                springfox-swagger2
                ${swagger.version}
            
            
            
                io.springfox
                springfox-swagger-ui
                ${swagger.version}
            
            
            
                io.jsonwebtoken
                jjwt
                ${jwt.version}
            
            
                com.alibaba
                fastjson
                ${fastjson.version}
            
            
                org.json
                json
                ${json.version}
            
        
    
    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    

2、在父工程创建子模块(以下都是maven工程)

1)common (删除 src目录 POM添加

pom



    
        acl_parent
        com.laptoy
        0.0.1-SNAPSHOT
    
    4.0.0
    common
    pom
    
        service_base
        spring_security
    
    
        8
        8
    
    
        
            org.springframework.boot
            spring-boot-starter-web
            provided 
        
        
        
            com.baomidou
            mybatis-plus-boot-starter
            provided 
        
        
        
            org.projectlombok
            lombok
            provided 
        
        
        
            io.springfox
            springfox-swagger2
            provided 
        
        
            io.springfox
            springfox-swagger-ui
            provided 
        
        
        
            org.springframework.boot
            spring-boot-starter-data-redis
        
        
        
            org.apache.commons
            commons-pool2
            2.6.0
        
    

●service_base:工具类



    
        common
        com.laptoy
        0.0.1-SNAPSHOT
    
    4.0.0
    service_base
    
        8
        8
    

●spring_security:权限配置



    
        common
        com.laptoy
        0.0.1-SNAPSHOT
        ../../pom.xml
    
    4.0.0
    spring_security
    
        8
        8
    
    
        
            com.laptoy
            service_base
            0.0.1-SNAPSHOT
        
        
        
            org.springframework.boot
            spring-boot-starter-security
        
        
            io.jsonwebtoken
            jjwt
        
    

2)infrastructure(删除 src目录 POM添加

pom



    
        acl_parent
        com.laptoy
        0.0.1-SNAPSHOT
    
    4.0.0
    infrastructure
    pom
    
        api_gateway
    
    
        8
        8
    

●api_gateway:网关



    
        infrastructure 
        com.laptoy
        0.0.1-SNAPSHOT
        ../../pom.xml
    
    4.0.0
    api_gateway
    
        8
        8
    
    
        
            com.laptoy
            service_base
            0.0.1-SNAPSHOT
        
        
            org.springframework.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        
        
            org.springframework.cloud
            spring-cloud-starter-gateway
        
        
        
            com.google.code.gson
            gson
        
        
        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        
    

3)service(删除 src目录 POM添加

pom



    
        acl_parent
        com.laptoy
        0.0.1-SNAPSHOT
    
    4.0.0
    service
    pom
    
        service_acl
    
    
        8
        8
    
    
        
            com.laptoy
            service_base
            0.0.1-SNAPSHOT
        
        
        
            org.springframework.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        
        
        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
            com.baomidou
            mybatis-plus-boot-starter
        
        
        
            io.springfox
            springfox-swagger2
        
        
            io.springfox
            springfox-swagger-ui
        
        
        
            mysql
            mysql-connector-java
        
        
        
            org.apache.velocity
            velocity-engine-core
        
        
        
            org.projectlombok
            lombok
        
        
        
            com.google.code.gson
            gson
        
    
    
        
            
                src/main/java
                
                    **/*.xml
                
                false
            
        
    

●service_acl:权限管理微服务模块



    
        service
        com.laptoy
        0.0.1-SNAPSHOT
    
    4.0.0
    service_acl
    
        8
        8
    
    
        
            com.laptoy
            spring_security
            0.0.1-SNAPSHOT
        
        
            com.alibaba
            fastjson
        
    

4、security 工具类 1、密码处理工具类

package com.laptoy.security.security;
import com.laptoy.utils.utils.MD5;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
/**
 * 密码处理工具类
 */
@Component
public class DefaultPasswordEncoder implements PasswordEncoder {
    public DefaultPasswordEncoder() {
        this(-1);
    }
    public DefaultPasswordEncoder(int strength) {
    }
    // 进行 MD5 加密
    @Override
    public String encode(CharSequence rawPassword) {
        return MD5.encrypt(rawPassword.toString());
    }
    /**
     * 传入的密码 与 数据库密码进行比较
     *
     * @param rawPassword     传入的密码
     * @param encodedPassword 数据库中的密码
     */
    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        return encodedPassword.equals(MD5.encrypt(rawPassword.toString()));
    }
}

2、Token工具类

package com.laptoy.security.security;
import io.jsonwebtoken.CompressionCodecs;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
public class TokenManager {
    // token 有效事件
    private long tokenExpiration = 24 * 60 * 60 * 1000;
    // 编码密钥用于签名
    private String tokenSignKey = "123456";
    // 1、根据用户名生成token
    public String createToken(String username) {
        String token = Jwts.builder().setSubject(username)
                .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
                .signWith(SignatureAlgorithm.HS512, tokenSignKey)
                .compressWith(CompressionCodecs.GZIP)
                .compact();
        return token;
    }
    // 2、根据token字符串得到用户信息
    public String getUserInfoFormToken(String token) {
        String userInfo = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody().getSubject();
        return userInfo;
    }
    // 3、删除token
    public void removeToken(String token) {
    }
}

3、退出处理器

package com.laptoy.security.security;
import com.laptoy.utils.utils.R;
import com.laptoy.utils.utils.ResponseUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class TokenLogoutHandler implements LogoutHandler {
    private TokenManager tokenManager;
    @Autowired
    private RedisTemplate redisTemplate;
    //构造方法
    public TokenLogoutHandler(TokenManager tokenManager, RedisTemplate redisTemplate) {
        this.tokenManager = tokenManager;
        this.redisTemplate = redisTemplate;
    }
    @Override
    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
        // 从header获取token
        String token = request.getHeader("token");
        if (token != null) {
            // 从header移除token
            tokenManager.removeToken(token);
            // 从token获取用户名
            String username = tokenManager.getUserInfoFormToken(token);
            // 从redis移除token
            redisTemplate.delete(username);
        }
        ResponseUtil.out(response, R.ok());
    }
}

4、未授权统一处理类

public class UnAuthEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        ResponseUtil.out(response, R.error());
    }
}

文章来源:https://blog.csdn.net/qq_52495761/article/details/138763893



微信扫描下方的二维码阅读本文

© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容