SpringBoot整合Spring Security OAuth2.0认证授权

  • Post author:
  • Post category:其他




一、集成SpringBoot



1.1 集成SpringBoot



1.1.1 创建SpringBoot工程和引入依赖

<?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 https://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.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.sun.security</groupId>
    <artifactId>security-spring-boot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>security-spring-boot</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>
        <!-- 以下是>spring boot依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- 以下是>spring security依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <!-- 以下是jsp依赖-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <scope>provided</scope>
        </dependency>
        <!--jsp页面使用jstl标签 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <!--用于编译jsp -->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

    </dependencies>


    <build>
        <finalName>security-springboot</finalName>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <version>2.2</version>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                </plugin>

                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <configuration>
                        <skipTests>true</skipTests>
                    </configuration>
                </plugin>

                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <configuration>
                        <encoding>utf-8</encoding>
                        <useDefaultDelimiters>true</useDefaultDelimiters>
                        <resources>
                            <resource>
                                <directory>src/main/resources</directory>
                                <filtering>true</filtering>
                                <includes>
                                    <include>**/*</include>
                                </includes>
                            </resource>
                            <resource>
                                <directory>src/main/java</directory>
                                <includes>
                                    <include>**/*.xml</include>
                                </includes>
                            </resource>
                        </resources>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>



1.1.2 编写配置文件

server.port=8080
server.servlet.context-path=/security-springboot
spring.application.name = security-springboot

spring.mvc.view.prefix=/WEB-INF/view/
spring.mvc.view.suffix=.jsp



1.1.3 Servlet Context配置

/**
 * 相当于springmvc.xml
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {
    //默认Url根路径跳转到/login,此url为spring security提供
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("redirect:/login");
    }

}



1.1.4 安全配置

/**
 * 安全配置(spring security)
 */
@Configuration
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();
    }
    //安全拦截机制(最重要)
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/session/r1").hasAuthority("p1")
                .antMatchers("/session/r2").hasAuthority("p2")
                .antMatchers("/session/**").authenticated()//所有/session/**的请求必须认证通过
                .anyRequest().permitAll()//除了/session/**,其他请求可以访问
                .and()
                .formLogin()//运行表单登录
                .successForwardUrl("/login-success");//登录访问接口
    }
}



1.2 工作原理



1.2.1 结构总览

Spring Security所解决的问题就是

安全访问控制

,而安全访问控制功能其实就是对所有进入系统的请求进行拦截,SpringMVC可以通过Filter或AOP等技术来实现,Spring Security对Web资源的保护是靠Filter实现的。

当初始化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)进行处理,下图是FilterChainProxy相关类的UML图示。

在这里插入图片描述

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

在这里插入图片描述

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


SecurityContextPersistenceFilter

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


UsernamePasswordAuthenticationFilter

用于处理来自表单提交的认证。该表单必须提供对应的用户名和密码,其内部还有登录成功或失败后进行处理的 AuthenticationSuccessHandler 和

AuthenticationFailureHandler,这些都可以根据需求做相关改变;


FilterSecurityInterceptor

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


ExceptionTranslationFilter

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



1.2.2 认证流程

在这里插入图片描述

让我们仔细分析认证过程:

  1. 用户提交用户名、密码被SecurityFilterChain中的 UsernamePasswordAuthenticationFilter 过滤器获取到,封装为请求Authentication,通常情况下是UsernamePasswordAuthenticationToken这个实现类。
  2. 然后过滤器将Authentication提交至认证管理器(AuthenticationManager)进行认证
  3. 认证成功后, AuthenticationManager 身份管理器返回一个被填充满了信息的(包括上面提到的权限信息,身份信息,细节信息,但密码通常会被移除) Authentication 实例。
  4. SecurityContextHolder 安全上下文容器将第3步填充了信息的 Authentication ,通过

    SecurityContextHolder.getContext().setAuthentication(…)方法,设置到其中。

    可以看出AuthenticationManager接口(认证管理器)是认证相关的核心接口,也是发起认证的出发点,它的实现类为ProviderManager。而Spring Security支持多种认证方式,因此ProviderManager维护着一个List 列表,存放多种认证方式,最终实际的认证工作是由

    AuthenticationProvider完成的。咱们知道web表单的对应的AuthenticationProvider实现类为

    DaoAuthenticationProvider,它的内部又维护着一个UserDetailsService负责UserDetails的获取。最终

    AuthenticationProvider将UserDetails填充至Authentication。

在这里插入图片描述


Authentication(认证信息)的结构:

public interface Authentication extends Principal, Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();

    Object getCredentials();

    Object getDetails();

    Object getPrincipal();

    boolean isAuthenticated();

    void setAuthenticated(boolean var1) throws IllegalArgumentException;
}

(1)getAuthorities(),权限信息列表,默认是GrantedAuthority接口的一些实现类,通常是代表权限信息的一系列字符串。

(2)getCredentials(),凭证信息,用户输入的密码字符串,在认证过后通常会被移除,用于保障安全。

(3)getDetails(),细节信息,web应用中的实现接口通常为 WebAuthenticationDetails,它记录了访问者的ip地址和sessionId的值。

(4)getPrincipal(),身份信息,大部分情况下返回的是UserDetails接口的实现类,UserDetails代表用户的详细信息,那从Authentication中取出来的UserDetails就是当前登录用户信息,它也是框架中的常用接口之一。



1.2.3 自定义UserDetailsService

/**
 * 自定义UserDetailsService查询
 */
@Service
public class SpringDataUserDetailsService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //登录账号
        System.out.println("username="+username);
        //根据账号去数据库查询
        //这里暂时使用静态数据
        UserDetails userDetails = User.withUsername(username).password("123").authorities("p1").build();
        return userDetails;
    }
}

去掉在WebSecurityConfig中定义的UserDetailsService从内存中拿取登录信息。



1.2.4 PasswordEncoder

1)采用字符串匹配方法,是明文的,输入密码是什么就拿什么密码对比

    @Bean
    public PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }

2)使用BCryptPasswordEncoder,需要对输入密码加密后对比

   @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }



1.2.5 授权流程

在这里插入图片描述

  1. 拦截请求,已认证用户访问受保护的web资源将被SecurityFilterChain中的 FilterSecurityInterceptor 的子类拦截。
  2. 获取资源访问策略,FilterSecurityInterceptor会从SecurityMetadataSource 的子类DefaultFilterInvocationSecurityMetadataSource 获取要访问当前资源所需要的权限Collection 。
  3. 最后,FilterSecurityInterceptor会调用 AccessDecisionManager 进行授权决策,若决策通过,则允许访问资源,否则将禁止访问。


投票分析

public interface AccessDecisionVoter<S> {
int ACCESS_GRANTED = 1;
int ACCESS_ABSTAIN = 0;
int ACCESS_DENIED =1;
boolean supports(ConfigAttribute var1);
boolean supports(Class<?> var1);
int vote(Authentication var1, S var2, Collection<ConfigAttribute> var3);
}

vote()方法的返回结果会是AccessDecisionVoter中定义的三个常量之一。ACCESS_GRANTED表示同意,ACCESS_DENIED表示拒绝,ACCESS_ABSTAIN表示弃权。如果一个AccessDecisionVoter不能判定当前

Authentication是否拥有访问对应受保护对象的权限,则其vote()方法的返回值应当为弃权ACCESS_ABSTAIN。



1.3 自定义认证



1.3.1 认证页面

在java同目录下新建webapp/WEB-INF/view/login.jsp



1.3.2 配置认证页面

在WebConfig.java中配置认证页面地址:

/**
 * 相当于springmvc.xml
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {

    //默认Url根路径跳转到/login,此url为spring security提供
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
//        registry.addViewController("/").setViewName("redirect:/login");//spring security提供的界面
        //自定义页面
       registry.addViewController("/").setViewName("redirect:/login-view");
        registry.addViewController("/login-view").setViewName("login");
    }
}



1.3.3 安全配置

在WebSecurityConfig中配置表章登录信息:

//安全拦截机制(最重要)
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/session/r1").hasAuthority("p1")
                .antMatchers("/session/r2").hasAuthority("p2")
                .antMatchers("/session/**").authenticated()//所有/session/**的请求必须认证通过
                .anyRequest().permitAll()//除了/session/**,其他请求可以访问
                .and()
                .formLogin()//允许表单登录
                .loginPage("/login-view")//登录页面
                .loginProcessingUrl("/login")
                .successForwardUrl("/login-success");//登录访问接口
    }



1.3.4 连接数据库



1.3.4.1 创建数据库

创建user_db数据库

CREATE TABLE `t_user` (
`id` bigint(20) NOT NULL COMMENT '用户id',
`username` varchar(64) NOT NULL,
`password` varchar(64) NOT NULL,
`fullname` varchar(255) NOT NULL COMMENT '用户姓名',
`mobile` varchar(11) DEFAULT NULL COMMENT '手机号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC



1.3.4.2 在application.properties配置dataSource

spring.datasource.url=jdbc:mysql://localhost:3306/user_db
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver‐class‐name=com.mysql.jdbc.Driver

添加依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql‐connector‐java</artifactId>
<version>5.1.47</version>
</dependency>

定义model

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserDto {
    private String id;
    private String username;
    private String password;
    private String fullname;
    private String mobile;
}

定义dao

@Repository
public class UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    //根据账号查询用户信息
    public UserDto getUserDtoByUsername(String username){
        String sql = "SELECT * FROM t_user where username = ?";
        List<UserDto> userDtoList = jdbcTemplate.query(sql, new Object[]{username}, new BeanPropertyRowMapper<>(UserDto.class));
        if(null != userDtoList && userDtoList.size() == 1){
            return userDtoList.get(0);
        }
        return null;
    }
}

定义service

/**
 * 自定义UserDetailsService查询
 */
@Service
public class SpringDataUserDetailsService implements UserDetailsService {

    @Autowired
    private UserDao userDao;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //根据用户名查询用户
        UserDto user = userDao.getUserDtoByUsername(username);
        if(null == user){
            //如果用户查不到,返回null,由provider来抛出异常
            return null;
        }
        //根据用户的id查询用户的权限
        List<String> permission = userDao.getPermissionByUserId(user.getId());
        //将permission转成数组
        String[] permissionArray = new String[permission.size()];
        permission.toArray(permissionArray);
        UserDetails userDetails = User.withUsername(user.getUsername()).password(user.getPassword()).authorities("p1").build();
        return userDetails;
    }
}



1.4 回话

用户认证通过后,为了避免用户的每次操作都进行认证可将用户的信息保存在会话中。spring security提供会话管理,认证通过后将身份信息放入SecurityContextHolder上下文,SecurityContext与当前线程进行绑定,方便获取用户身份。



1.4.1 获取用户身份

Spring Security获取当前登录用户信息的方法是SecurityContextHolder.getContext().getAuthentication()

 //获取当前用户信息
    private String getUername(){
        String username = null;
        //当前认证通过的用户身份
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        //用户身份
        Object principal = authentication.getPrincipal();
        if(null == principal){
            username = "匿名";
        }
        if(principal instanceof org.springframework.security.core.userdetails.UserDetails){
            UserDetails userDetails = (UserDetails) principal;
            username = userDetails.getUsername();
        }else {
            username = principal.toString();
        }
        return username;
    }



1.4.2 回话控制

配置WebSecurityConfig

//安全拦截机制(最重要)
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()//跨站请求伪造关闭
                .authorizeRequests()
                .antMatchers("/session/r1").hasAuthority("p1")
                .antMatchers("/session/r2").hasAuthority("p2")
                .antMatchers("/session/**").authenticated()//所有/session/**的请求必须认证通过
                .anyRequest().permitAll()//除了/session/**,其他请求可以访问
                .and()
                .formLogin()//允许表单登录
                .loginPage("/login-view")//登录页面
                .loginProcessingUrl("/login")
                .successForwardUrl("/login-success")//登录访问接口
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);//如果需要就创建一个Session(默认)登录时
    }

always:如果没有session存在就创建一个

ifRequired:如果需要就创建一个Session(默认)登录时

never:SpringSecurity 将不会创建Session,但是如果应用中其他地方创建了Session,那么Spring

Security将会使用它。

stateless:SpringSecurity将绝对不会创建Session,也不使用Session



1.5 退出

配置WebSecurityConfig

  //安全拦截机制(最重要)
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()//跨站请求伪造关闭
                .authorizeRequests()
//                .antMatchers("/session/r1").hasAuthority("p1")
//                .antMatchers("/session/r2").hasAuthority("p2")
                .antMatchers("/session/**").authenticated()//所有/session/**的请求必须认证通过
                .anyRequest().permitAll()//除了/session/**,其他请求可以访问
                .and()
                .formLogin()//允许表单登录
                .loginPage("/login-view")//登录页面
                .loginProcessingUrl("/login")
                .successForwardUrl("/login-success")//登录访问接口
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)//如果需要就创建一个Session(默认)登录时
                .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/login-view?logout");

    }

当退出操作出发时,将发生:

  • 使HTTP Session 无效
  • 清除 SecurityContextHolder
  • 跳转到 /login-view?logout



1.6 授权



1.6.1 授权分类

授权的方式包括 web授权和方法授权,web授权是通过 url拦截进行授权,方法授权是通过 方法拦截进行授权。他们都会调用accessDecisionManager进行授权决策,若为web授权则拦截器为FilterSecurityInterceptor;若为方法授权则拦截器为MethodSecurityInterceptor。如果同时通过web授权和方法授权则先执行web授权,再执行方法授权,最后决策通过,则允许访问资源,否则将禁止访问。

在这里插入图片描述



1.6.2 准备环境



1.6.2.1 数据库环境

在t_user数据库创建如下表:


角色表:

CREATE TABLE `t_role` (
`id` varchar(32) NOT NULL,
`role_name` varchar(255) DEFAULT NULL,
`description` varchar(255) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
`status` char(1) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_role_name` (`role_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
insert into `t_role`(`id`,`role_name`,`description`,`create_time`,`update_time`,`status`) values
('1','管理员',NULL,NULL,NULL,'');

用户角色关系表:

CREATE TABLE `t_user_role` (
`user_id` varchar(32) NOT NULL,
`role_id` varchar(32) NOT NULL,
`create_time` datetime DEFAULT NULL,
`creator` varchar(255) DEFAULT NULL,
PRIMARY KEY (`user_id`,`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
insert into `t_user_role`(`user_id`,`role_id`,`create_time`,`creator`) values
('1','1',NULL,NULL);

权限表:

CREATE TABLE `t_permission` (
`id` varchar(32) NOT NULL,
`code` varchar(32) NOT NULL COMMENT '权限标识符',
`description` varchar(64) DEFAULT NULL COMMENT '描述',
`url` varchar(128) DEFAULT NULL COMMENT '请求地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
insert into `t_permission`(`id`,`code`,`description`,`url`) values ('1','p1','测试资源
1','/session/r1'),('2','p3','测试资源2','/session/r2');

角色权限关系表:

CREATE TABLE `t_role_permission` (
`role_id` varchar(32) NOT NULL,
`permission_id` varchar(32) NOT NULL,
PRIMARY KEY (`role_id`,`permission_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
insert into `t_role_permission`(`role_id`,`permission_id`) values ('1','1'),('1','2');



1.6.3 添加dao、service

UserDao

 //根据用户id查询用户权限
    public List<String> getPermissionByUserId(String userId){
        String sql = "select * from t_permission where id in(\n" +
                "\tselect permission_id from t_role_permission where role_id in(\n" +
                "\t\tselect role_id from t_user_role where user_id = ? \n" +
                "\t)\n" +
                ")";
        List<PermissionDto> list = jdbcTemplate.query(sql, new Object[]{userId}, new BeanPropertyRowMapper<>(PermissionDto.class));
        List<String> permissionList = list.stream()
                .map(PermissionDto::getCode)
                .collect(Collectors.toList());
        return permissionList;
    }

修改SpringDataUserDetailsService

  @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //根据用户名查询用户
        UserDto user = userDao.getUserDtoByUsername(username);
        if(null == user){
            //如果用户查不到,返回null,由provider来抛出异常
            return null;
        }
        //根据用户的id查询用户的权限
        List<String> permission = userDao.getPermissionByUserId(user.getId());
        //将permission转成数组
        String[] permissionArray = new String[permission.size()];
        permission.toArray(permissionArray);
        UserDetails userDetails = User.withUsername(user.getUsername()).password(user.getPassword()).authorities(permissionArray).build();
        return userDetails;
    }

权限model

/**
 * 权限Dto
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PermissionDto {

    private String id;
    private String code;
    private String description;
    private String url;
}



1.6.4 web授权

配置WebSecurityConfig,注释掉权限分配,通过查询查询数据库赋予用户权限。

 //安全拦截机制(最重要)
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()//跨站请求伪造关闭
                .authorizeRequests()
//                .antMatchers("/session/r1").hasAuthority("p1")
//                .antMatchers("/session/r2").hasAuthority("p2")
                .antMatchers("/session/**").authenticated()//所有/session/**的请求必须认证通过
                .anyRequest().permitAll()//除了/session/**,其他请求可以访问
                .and()
                .formLogin()//允许表单登录
                .loginPage("/login-view")//登录页面
                .loginProcessingUrl("/login")
                .successForwardUrl("/login-success")//登录访问接口
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)//如果需要就创建一个Session(默认)登录时
                .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/login-view?logout");

    }



1.6.5 方法授权

授权有三类:@PreAuthorize,@PostAuthorize, @Secured

一般使用@PreAuthorize

在WebSecurityConfig中添加注解@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)

/**
 * 安全配置(spring security)
 */
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
}

在controller方法中添加注解@PreAuthorize(“hasAuthority(‘p2’)”)

  /**
     * 测试资源2
     * @return
     */
    @GetMapping(value = "/session/r2",produces = {"text/plain;charset=UTF-8"})
    @PreAuthorize("hasAuthority('p2')")
    public String r2(){
        return getUername()+" 访问资源2";
    }



版权声明:本文为sunpanlong123原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。