java认证授权(Spring Security)

目录

1、Spring Security介绍

2、认证授权入门

2.2.1 创建认证服务工程

1、部署认证服务工程

2、配置Spring Security所需要的依赖

3、初始工程自带了一个Controller类,如下

4、需要进行安全配置。

3、授权测试

1、配置用户拥有哪些权限。

2、指定资源与权限的关系。

4、工作原理

Spring Security的执行流程如下:


1、Spring Security介绍

        认证功能几乎是每个项目都要具备的功能,并且它与业务无关,市面上有很多认证框架,如:Apache Shiro、CAS、Spring Security等。由于本项目基于Spring Cloud技术构建,Spring Security是spring家族的一份子且和Spring Cloud集成的很好,所以本项目选用Spring Security作为认证服务的技术框架。

Spring Security 是一个功能强大且高度可定制的身份验证和访问控制框架,它是一个专注于为 Java 应用程序提供身份验证和授权的框架。

项目主页:https://spring.io/projects/spring-security

Spring cloud Security: https://spring.io/projects/spring-cloud-security

2、认证授权入门

2.2.1 创建认证服务工程

下边我们使用Spring Security框架快速构建认证授权功能体系。

1、部署认证服务工程

创建一个xuecheng-plus-auth工程到自己的工程目录下。

此工程是一个普通的spring boot工程,可以连接数据库。

此工程不具备认证授权的功能。

2、配置Spring Security所需要的依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>

3、初始工程自带了一个Controller类,如下

package com.xuecheng.auth.controller;

import com.xuecheng.ucenter.mapper.XcUserMapper;
import com.xuecheng.ucenter.model.po.XcUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Mr.Zhang
 * @version 1.0
 * @description 测试controller
 * @date 2023/3/16 10:25
 */
@Slf4j
@RestController
public class LoginController {

    @Autowired
    XcUserMapper userMapper;


    @RequestMapping("/login-success")
    public String loginSuccess() {

        return "登录成功";
    }


    @RequestMapping("/user/{id}")
    public XcUser getuser(@PathVariable("id") String id) {
        XcUser xcUser = userMapper.selectById(id);
        return xcUser;
    }

    @RequestMapping("/r/r1")
    public String r1() {
        return "访问r1资源";
    }

    @RequestMapping("/r/r2")
    public String r2(){
        return "访问r2资源";
    }


}

4、需要进行安全配置。

建一个WebSecurityConfig.java到config下需要三部分内容:

1、用户信息

在内存配置两个用户:zhangsan、lisi

zhangsan用户拥有的权限为p1

lisi用户拥有的权限为p2

2、密码方式

暂时采用明文方式

3、安全拦截机制

/r/**开头的请求需要认证

登录成功到成功页面

代码如下:

package com.xuecheng.auth.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

/**
 * @author Mr.M
 * @version 1.0
 * @description 安全管理配置
 * @date 2023/3/16 10:25
 */
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


    //配置用户信息服务
    @Bean
    public UserDetailsService userDetailsService() {
        //这里配置用户信息,这里暂时使用这种方式将用户存储在内存中
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("zhangsan").password("123").authorities("p1").build());
        manager.createUser(User.withUsername("lisi").password("456").authorities("p2").build());
        return manager;
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
//        //密码为明文方式
        return NoOpPasswordEncoder.getInstance();
//        return new BCryptPasswordEncoder();
    }

    //配置安全拦截机制
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/r/**").authenticated()//访问/r开始的请求需要认证通过
                .anyRequest().permitAll()//其它请求全部放行
                .and()
                .formLogin().successForwardUrl("/login-success");//登录成功跳转到/login-success
    }



}

重启工程

1、访问http://localhost:63070/auth/user/52  可以正常访问

2、访问http://localhost:63070/auth/r/r1 显示登录页面

账号zhangsan,密码为123,如果输入的密码不正确会认证失败,输入正确显示登录成功。

为什么http://localhost:63070/auth/user/52  可以正常访问,访问http://localhost:63070/auth/r/r1 显示登录页面?

http.logout().logoutUrl("/logout");配置了退出页面,认证成功后访问/logout可退出登录

访问:http://localhost:63070/auth/login  端口号配自己电脑的我配的端口是63070

3、授权测试

用户认证通过去访问系统资源时spring security进行授权控制,判断用户是否有该资源的访问权限,如果有则继续访问,如果没有则拒绝访问。

下边测试授权功能:

1、配置用户拥有哪些权限。

在WebSecurityConfig类配置zhangsan拥有p1权限,lisi拥有p2权限。

//配置用户信息服务
@Bean
public UserDetailsService userDetailsService() {
    //这里配置用户信息,这里暂时使用这种方式将用户存储在内存中
    InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
    manager.createUser(User.withUsername("zhangsan").password("123").authorities("p1").build());
    manager.createUser(User.withUsername("lisi").password("456").authorities("p2").build());
    return manager;
}

2、指定资源与权限的关系。

什么是系统的资源?

比如:查询一个用户的信息,用户信息就是系统的资源,要访问资源需要通过URL,所以我们在controller中定义的每个http的接口就是访问资源的接口。

下边在controller中配置/r/r1需要p1权限,/r/r2需要p2权限。

hasAuthority('p1')表示拥有p1权限方可访问。

代码如下:

@RequestMapping("/r/r1")
@PreAuthorize("hasAuthority('p1')")//拥有p1权限方可访问
public String r1() {
    return "访问r1资源";
}

@RequestMapping("/r/r2")
@PreAuthorize("hasAuthority('p2')")//拥有p2权限方可访问
public String r2(){
    return "访问r2资源";
}

现在重启工程。

当访问以/r/开头的url时会判断用户是否认证,如果没有认证则跳转到登录页面,如果已经认证则判断用户是否具有该URL的访问权限,如果具有该URL的访问权限则继续,否则拒绝访问。

例如:

访问/r/r1,使用zhangsan登录可以正常访问,因为在/r/r1的方法上指定了权限p1,zhangsan用户拥有权限p1,所以可以正常访问。

访问/r/r1,使用lisi登录则拒绝访问,由于lisi用户不具有权限p1需要拒绝访问

注意:如果访问上不加@PreAuthorize,此方法没有授权控制。

整理授权的过程见下图所示:

4、工作原理

通过测试认证和授权两个功能,我们了解了Spring Security的基本使用方法,下边了解它的工作流程。

Spring Security所解决的问题就是安全访问控制,而安全访问控制功能其实就是对所有进入系统的请求进行拦截,校验每个请求是否能够访问它所期望的资源。根据前边知识的学习,可以通过Filter或AOP等技术来实现,Spring Security对Web资源的保护是靠Filter实现的,所以从这个Filter来入手,逐步深入Spring Security原理。

        当初始化Spring Security时,会创建一个名为SpringSecurityFilterChain的Servlet过滤器,类型为 org.springframework.security.web.FilterChainProxy,它实现了javax.servlet.Filter,因此外部的请求会经过此类,下图是Spring Security过虑器链结构图:

FilterChainProxy是一个代理,真正起作用的是FilterChainProxy中SecurityFilterChain所包含的各个Filter,同时这些Filter作为Bean被Spring管理,它们是Spring Security核心,各有各的职责,但他们并不直接处理用户的认证,也不直接处理用户的授权,而是把它们交给了认证管理器(AuthenticationManager)和决策管理器(AccessDecisionManager)进行处理。

spring Security功能的实现主要是由一系列过滤器链相互配合完成。

下面介绍过滤器链中主要的几个过滤器及其作用:

SecurityContextPersistenceFilter 这个Filter是整个拦截过程的入口和出口(也就是第一个和最后一个拦截器),会在请求开始时从配置好的 SecurityContextRepository 中获取 SecurityContext,然后把它设置给 SecurityContextHolder。在请求完成后将 SecurityContextHolder 持有的 SecurityContext 再保存到配置好的 SecurityContextRepository,同时清除 securityContextHolder 所持有的 SecurityContext;

UsernamePasswordAuthenticationFilter 用于处理来自表单提交的认证。该表单必须提供对应的用户名和密码,其内部还有登录成功或失败后进行处理的 AuthenticationSuccessHandler 和 AuthenticationFailureHandler,这些都可以根据需求做相关改变;

FilterSecurityInterceptor 是用于保护web资源的,使用AccessDecisionManager对当前用户进行授权访问,前面已经详细介绍过了;

ExceptionTranslationFilter 能够捕获来自 FilterChain 所有的异常,并进行处理。但是它只会处理两类异常:AuthenticationException 和 AccessDeniedException,其它的异常它会继续抛出。

Spring Security的执行流程如下:

  1. 用户提交用户名、密码被SecurityFilterChain中的UsernamePasswordAuthenticationFilter过滤器获取到,封装为请求Authentication,通常情况下是UsernamePasswordAuthenticationToken这个实现类。
  1. 然后过滤器将Authentication提交至认证管理器(AuthenticationManager)进行认证
  1. 认证成功后,AuthenticationManager身份管理器返回一个被填充满了信息的(包括上面提到的权限信息,身份信息,细节信息,但密码通常会被移除)Authentication实例。
  1. SecurityContextHolder安全上下文容器将第3步填充了信息的Authentication,通过SecurityContextHolder.getContext().setAuthentication(…)方法,设置到其中。
  1.         可以看出AuthenticationManager接口(认证管理器)是认证相关的核心接口,也是发起认证的出发点,它的实现类为ProviderManager。而Spring Security支持多种认证方式,因此ProviderManager维护着一个List<AuthenticationProvider>列表,存放多种认证方式,最终实际的认证工作是由AuthenticationProvider完成的。咱们知道web表单的对应的AuthenticationProvider实现类为DaoAuthenticationProvider,它的内部又维护着一个UserDetailsService负责UserDetails的获取。最终AuthenticationProvider将UserDetails填充至Authentication。

猜你喜欢

转载自blog.csdn.net/Relievedz/article/details/129581260