美文网首页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