美文网首页springbootspring security
springBoot整合spring security(环境为2

springBoot整合spring security(环境为2

作者: 程序员小杰 | 来源:发表于2020-01-31 15:00 被阅读0次

导入依赖

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

创建一个 HelloController:

@RestController
public class HelloController {

    @GetMapping("/he")
    public String he() {
        return "hello Security";
    }
}

访问http://localhost:8081/he
当用户从浏览器发送请求访问 /he接口时,客户端重定向到 /login 页面,用户在 /login 页面登录,登陆成功之后,就会自动跳转到 /he接口。

image.png
输入用户名和密码,用户名默认为user,密码会打印在控制台上
image.png image.png
image.png

这个随机生成的密码,每次启动时都会变。对登录的用户名/密码进行配置,有三种不同的方式:

在 application.properties或者application.yml 中进行配置
通过 Java 代码配置在内存中
通过 Java 从数据库中加载(下一篇博文介绍)

配置文件配置用户名/密码

properties

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

yml

spring:
  security:
    user:
      name: admin
      password: 123
      roles:
      - admin

Java 配置用户名/密码

创建一个 Spring Security 的配置类,继承 WebSecurityConfigurerAdapter 类


import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import com.fasterxml.jackson.databind.ObjectMapper;
@Configuration
public class SecurityConfig<V> extends WebSecurityConfigurerAdapter{

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
     
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
        .withUser("admin").password("$2a$10$5cfZHg5x9jRNPSHrVnPSE.YEcoqQkfO5IlpxY1R1Jo3u.1JsZPoiW")
        .roles("admin")  //123
        .and()
        .withUser("user").password("$2a$10$TawHx0DjM.trtcCdKumH0uCLqNF7UQVmNbAXi/NXYzv0GDQ6YOU8i")
        .roles("user");  //123
    }

}
public static void main(String[] args) {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        System.out.println(bCryptPasswordEncoder.encode("123"));
        System.out.println(bCryptPasswordEncoder.encode("123"));

    }

这里我们在 configure 方法中配置了两个用户,用户的密码都是加密之后的字符串(明文是 123),从 Spring5 开始,强制要求密码要加密,如果非不想加密,可以使用一个过期的 PasswordEncoder 的实例 NoOpPasswordEncoder,但是不建议这么做,毕竟不安全。


image.png

登录配置


import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import com.fasterxml.jackson.databind.ObjectMapper;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()       //开启配置
        .antMatchers("/admin/**").hasRole("admin")    //访问/admin/**下的路径,必须具备admin身份
        .antMatchers("/user/**").hasAnyRole("admin","user")   //访问/user/**下的路径,必须具备admin和user中其中一个身份
        .antMatchers("/db/**").access("hasAnyRole('admin','user')") //访问/db/**下的路径,必须具备admin和user中其中一个身份
        .anyRequest()    //其他请求
        .authenticated()   //已验证   也就是其他请求只需要登录就能访问
        .and()
        .formLogin()  //表单登录
        .loginProcessingUrl("/doLogin")   //登录接口 如果要用postmall测试
        .loginPage("/login1")    //登录页面
        .usernameParameter("uname")  //自定义登录key 默认为 username
        .passwordParameter("upwd")   //自定义登录key  默认为 password
        .successHandler(new AuthenticationSuccessHandler() {   //登录成功处理 直接返回json
            
            @Override
            public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse res,
                    Authentication authentication) throws IOException, ServletException {
                res.setContentType("application/json;charset=utf-8");
                PrintWriter out = res.getWriter();
                HashMap<String, Object> map = new HashMap<String, Object>();
                map.put("status", 200);
                map.put("msg", authentication.getPrincipal()); //登录信息
                out.write(new ObjectMapper().writeValueAsString(map));
                out.flush();
                out.close();
            }
        })   //前后端分离使用
        .failureHandler(new AuthenticationFailureHandler() {   //登录失败处理
            
            @Override
            public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp,
                    AuthenticationException e) throws IOException, ServletException {
                resp.setContentType("application/json;charset=utf-8");
                PrintWriter out = resp.getWriter();
                HashMap<String, Object> map = new HashMap<String, Object>();
                map.put("status", 200);
                if(e instanceof LockedException) {
                    map.put("msg", "账号被锁定");
                }else if(e instanceof BadCredentialsException) {
                    map.put("msg", "用户名或者密码错误");
                }else if(e instanceof DisabledException) {
                    map.put("msg", "账户被禁用");
                }else if(e instanceof AccountExpiredException) {
                    map.put("msg", "账户过期");
                }else if(e instanceof CredentialsExpiredException) {
                    map.put("msg", "密码过期");
                }else {
                    map.put("msg", "登录失败");
                }
                out.write(new ObjectMapper().writeValueAsString(map));
                out.flush();
                out.close();
            }
        })
        .permitAll()
        .and()
        .logout()
        .logoutUrl("/logout")
        .logoutSuccessHandler(new LogoutSuccessHandler() {  //注销成功
            
            @Override
            public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse res, Authentication authentication)
                    throws IOException, ServletException {
                    res.setContentType("application/json;charset=utf-8");
                    PrintWriter out = res.getWriter();
                    HashMap<String, Object> map = new HashMap<String, Object>();
                    map.put("status", 200);
                    map.put("msg", "注销成功");
                    out.write(new ObjectMapper().writeValueAsString(map));
                    out.flush();
                    out.close();
            }
        })
        .and()
        .csrf().disable();  // 关闭csrf 以便我们在 postman类似的软件测试被系统给拦截了


    }
    }

如果不是前后端分离项目,
登录成功:使用.successForwardUrl("/index") //登录成功跳转地址


image.png

登录失败:


image.png

controller层添加一些接口以便我们测试

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/he")
    public String he() {
        return "hello Security";
    }
    
    @GetMapping("/admin/he")
    public String admin() {
        return "hello admin";
    }
    
    @GetMapping("/user/he")
    public String user() {
        return "hello user";
    }
    
    @GetMapping("/db/he")
    public String db() {
        return "hello db";
    }
    
    @GetMapping("/login1")
    public String login1() {
        return "hello login1";
    }
}

通过postman调用:localhost:8081/he,来到登录页,因为没有进行登录


image.png

调用:localhost:8081/doLogin 登录user账户

image.png

再次调用:localhost:8081/he


image.png

调用:localhost:8081/admin/he(没有权限)


image.png
调用:localhost:8081/user/he
image.png
调用:localhost:8081/db/he
image.png

登录admin账户


image.png
调用:localhost:8081/admin/he
image.png

对方法进行保护

要开启Spring方法级安全,在添加了@Configuration注解的类上再添加@EnableGlobalMethodSecurity注解即可


image.png
@EnableGlobalMethodSecurity(prePostEnabled = true)

创建Service层添加测试方法

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;

@Service
public class HelloService {
 
    @PreAuthorize("hasRole('admin')")  //拥有admin权限
    public String admin() {
        return "hell admin";
    }
    
    @PreAuthorize("hasRole('user')")     //拥有user权限
    public String user() {
        return "hell user";
    }
    
    
    @PreAuthorize("hasAnyRole('admin','user')")  //拥有admin权限和user权限其中一个
    public String db() {
        return "hell db";
    }
}

Controller层也提供几个登录就可以访问方法

    @Autowired
    HelloService helloService;
    
    @GetMapping("/helloAdmin")
    public String helloAdmin() {
        return helloService.admin();
    }
    
    @GetMapping("/helloUser")
    public String helloUser() {
        return helloService.user();
    }
    
    @GetMapping("/hellodb")
    public String hellodb() {
        return helloService.db();
    }

登录user账户调用:localhost:8081/helloUser(可以调用)

image.png
调用:localhost:8081/hellodb(可以调用)
image.png
调用:localhost:8081/helloAdmin(不可以调用,没有权限)
image.png
登录admin账户调用:localhost:8081/helloAdmin(可以调用)
image.png
调用:localhost:8081/hellodb(可以调用)
image.png
调用:localhost:8081/helloUser(不可以调用,没有权限)
image.png
@EnableGlobalMethodSecurity注解详细说明推荐:https://www.jianshu.com/p/77b4835b6e8e

注销

image.png

相关文章

网友评论

    本文标题:springBoot整合spring security(环境为2

    本文链接:https://www.haomeiwen.com/subject/znsgthtx.html