spingsecurity使用和说明

 

1、引入spingsecurity依赖

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

启动项目访问 http://localhost:8080/login  账号:user 密码:控制台系统生成的

2、配置自定义用户名密码

配置文件配置

# 应用服务 WEB 访问端口
server.port=8080

spring.security.user.name=admin
spring.security.user.password=123456

或者 方法中配置(优先级高)

package com.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    // 这种方式认证用户名和密码比配置容器中 UserDetailsService方法级别高
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().
                withUser("root"). // 用户名
                password(this.passwordEncoder().encode("123")) 密码
                .roles("admin");  //角色
    }

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

3、获取当前登录用户信息

package com.example.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.security.Principal;

@RestController
public class CurrentLoginUserInfoController {

    /**
     * 从当前请求对象中获取
     */
    @GetMapping("/getLoginUserInfo")
    public Principal getLoginUserInfo(Principal principle){
            return principle;
    }
    /**
     *从当前请求对象中获取
     */
    @GetMapping("/getLoginUserInfo1")
    public Authentication getLoginUserInfo1(Authentication authentication){
        return authentication;
    }

    /**
     * 从SecurityContextHolder获取
     * @return
     */
    @GetMapping("/getLoginUserInfo2")
    public Authentication getLoginUserInfo(){
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return authentication;
    }
}

 

4、授权(对URL进行授权)

实现了认证功能,但是受保护的资源是默认的,默认所有认证(登录)用户均可以访问所有资源,不能根据实际情况进行角色管理,要实现授权功能,需重写WebSecurityConfigureAdapter 中的一个configure方法

package com.example.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                //角色student或者teacher都可以访问/student/** 这样的url
                .mvcMatchers("/student/*").hasAnyRole("student", "teacher")
                // 角色teacher 可以访问teacher/**
                .mvcMatchers("/teacher/**").hasRole("teacher")
                //权限admin:query 可以访问/admin**
//                .mvcMatchers("/admin/**").hasAuthority("admin:query")
                //角色teacher 或者权限admin:query 觉可以访问admin/**
                .mvcMatchers("/admin/**").access("hasRole('teacher') or hasAuthority('admin:query')")
                //任何请求均需要认证
                .anyRequest().authenticated();
        //使用表单登录
        http.formLogin();
    }
}

5、授权(方法级别的权限控制)

我们可以通过注解灵活的配置方法安全,我们先通过@EnableGlobalMethodSecurity开启基于注解的安全配置。

 WebSecurityConfig方法

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.WebSecurityConfigurerAdapter;

@EnableGlobalMethodSecurity(prePostEnabled = true) //开启全局方法安全,启用预授权注解和后授权注解
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //controller 的权限配置,可以在这里配置
        http.authorizeRequests().anyRequest().authenticated();//任何请求均需要认证
        http.formLogin().permitAll();  //放开登录页面及登录接口
    }
}

MySecurityUserConfig方法

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@Configuration
@Slf4j
public class MySecurityUserConfig {
    @Bean
    public UserDetailsService userDetailsService(){
        //新建用户
        UserDetails user1= User.builder()
                .username("eric")
                .password(passwordEncoder().encode("123456")) //用户密码必须加密
                .roles("student") //角色  转变成权限(ROLE_student)
                .build();
        UserDetails user2= User.builder()
                .username("thomas")
                .password(passwordEncoder().encode("123456")) //用户密码必须加密
                .authorities("teacher:query")
                .build();
        UserDetails user3= User.builder()
                .username("admin")
                .password(passwordEncoder().encode("123456")) //用户密码必须加密
                .authorities("teacher:query","teacher:add","teacher:update","teacher:delete")
                .build();
        InMemoryUserDetailsManager userDetailsService =new InMemoryUserDetailsManager();
        userDetailsService.createUser(user1);
        userDetailsService.createUser(user2);
        userDetailsService.createUser(user3);
        return  userDetailsService;

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

TeacherService业务接口

package com.example.service;

public interface TeacherService {
    String add();
    String update();
    String delete();
    String query();
}

TeacherServiceImpl业务接口实现类

package com.example.service.impl;

import com.powernode.service.TeacherService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class TeacherServiceImpl implements TeacherService {
    @Override
    @PreAuthorize("hasAuthority('teacher:add')") //预授权
    public String add() {
        log.info("添加教师成功");
        return "添加教师成功";
    }

    @Override
    @PreAuthorize("hasAnyAuthority('teacher:update')") //预授权
    public String update() {
        log.info("修改教师成功");
        return "修改教师成功";
    }

    @Override
    @PreAuthorize("hasAuthority('teacher:delete')") //预授权
    public String delete() {
        log.info("删除教师成功");
        return "删除教师成功";
    }

    @Override
    @PreAuthorize("hasAnyAuthority('teacher:query')") //预授权
    public String query() {
        log.info("查询教师成功");
        return "查询教师成功";
    }
}

TeacherController控制类

package com.example.controller;

import com.powernode.service.TeacherService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
@RequestMapping("/teacher")
@Slf4j
public class TeacherController {
    @Resource
    private TeacherService teacherService;

    @GetMapping("/query")
    public String queryInfo() {
        return teacherService.query();
    }

    @GetMapping("/add")
    public String addInfo() {
        return teacherService.add();
    }

    @GetMapping("/update")
    public String updateInfo() {
        int a=10;
        log.info("进入更新教师controller");
        return teacherService.update();
    }

    @GetMapping("/delete")
    public String deleteInfo() {
        return teacherService.delete();
    }
}

6、认证返回json统一返回数据格式

统一消息格式对象类 HttpResult

package com.example.vo;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor //用于生成类的构造函数。
@NoArgsConstructor //用于生成无参构造函数
@Builder //生成建造者模式
public class HttpResult {
    private Integer code; //返回给前端的自定义响应码
    private String msg;  // 返回给前端的消息
    private Object data; //返回给前端的数据
}

在配置包里新建4个配置类

AppAutheticationSuccessHandler //配置认证成功处理器
AppAuthenticationFailHandler  //配置认证失败处理器
AppLogoutSuccessHanlder    //配置退出成功处理器
AppAccessDenyHanlder //配置访问拒绝处理器

import com.fasterxml.jackson.databind.ObjectMapper;
import com.example.vo.HttpResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 认证成功就会调用该接口里的方法
 */
@Component
@Slf4j
public class AppAutheticationSuccessHandler implements AuthenticationSuccessHandler {
    @Resource
    private ObjectMapper objectMapper;  //可以进行序列化(json)和反序列化,
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        HttpResult httpResult=HttpResult.builder()
                .code(1)
                .msg("登录成功")
                .build();
        String responseJson = objectMapper.writeValueAsString(httpResult);
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.println(responseJson);
        writer.flush();
    }
}
import com.fasterxml.jackson.databind.ObjectMapper;
import com.example.vo.HttpResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@Component
@Slf4j
public class AppAuthenticationFailHandler implements AuthenticationFailureHandler {
    @Resource
    private ObjectMapper objectMapper;
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        HttpResult httpResult=HttpResult.builder()
                .code(0)
                .msg("登录失败")
                .build();
        String responseJson = objectMapper.writeValueAsString(httpResult);

        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.println(responseJson);
        writer.flush();
    }
}
import com.fasterxml.jackson.databind.ObjectMapper;
import com.example.vo.HttpResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;


@Component
@Slf4j
public class AppLogoutSuccessHanlder implements LogoutSuccessHandler {
    @Resource
    private ObjectMapper objectMapper;
    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        HttpResult httpResult=HttpResult.builder()
                .code(1)
                .msg("退出成功")
                .build();
        String responseJson = objectMapper.writeValueAsString(httpResult);

        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.println(responseJson);
        writer.flush();
    }
}
import com.fasterxml.jackson.databind.ObjectMapper;
import com.example.vo.HttpResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@Component
@Slf4j
public class AppAccessDenyHanlder implements AccessDeniedHandler {
    @Resource
    private ObjectMapper objectMapper;
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        HttpResult httpResult=HttpResult.builder()
                .code(0)
                .msg("您没有权限访问该资源!!")
                .build();
        String responseJson = objectMapper.writeValueAsString(httpResult);

        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.println(responseJson);
        writer.flush();
    }
}

 认证用户类 UserDetailsService ,修改容器中认证用户类


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

/**
 * 定义一个bean,用户详情服务接口
 */
@Configuration
public class MySecurityUserConfig {
    @Bean
    public UserDetailsService userDetailsService(){
        //创建了2个用户,系统的用户
        UserDetails user1= User.builder()
                .username("eric")
                .password(passwordEncoder().encode("123456"))
                .roles("student")  //角色的前面加上ROLE_student 就变成了权限
                .build();
        UserDetails user2= User.builder()
                .username("thomas")
                .password(passwordEncoder().encode("123456"))
                .roles("teacher") //ROLE_teacher
                .build();
        InMemoryUserDetailsManager userDetailsService=new InMemoryUserDetailsManager();
        userDetailsService.createUser(user1);
        userDetailsService.createUser(user2);
        return userDetailsService;

    }
    /**
     * 自定义用户必须配置密码编码器
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

}

在WebSecurityConfig中配置各种情况的处理器

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import javax.annotation.Resource;

@Configuration
@Slf4j
public class WebSecurityConfig  extends WebSecurityConfigurerAdapter {
    @Resource
    private AppAutheticationSuccessHandler appAutheticationSuccessHandler;
    @Resource
    private AppAuthenticationFailHandler appAuthenticationFailHandler;
    @Resource
    private AppLogoutSuccessHanlder appLogoutSuccessHanlder;
    @Resource
    private AppAccessDenyHanlder appAccessDenyHanlder;
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .mvcMatchers("/student/**")
                .hasRole("student")
                .anyRequest().authenticated();
        //设置登录成功的处理器
        http.formLogin()
                .successHandler(appAutheticationSuccessHandler) //配置认证成功处理器
                .failureHandler(appAuthenticationFailHandler) //配置认证失败处理器
                .permitAll();
        http.logout().logoutSuccessHandler(appLogoutSuccessHanlder);//配置退出成功处理器
        //配置访问拒绝处理器
        http.exceptionHandling().accessDeniedHandler(appAccessDenyHanlder);
    }
}

 

posted @ 2024-02-05 15:24  大司徒  阅读(12)  评论(0编辑  收藏  举报