权限-基于内存的方式实现security(三)

  1. 新建springboot项目

相关依赖

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--security-->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
    </dependencies>
  1. security基于内存的方式实现权限认证

application.properties

server.port=8080

config

SecurityConfig

package com.dong.security.config;

import org.springframework.context.annotation.Bean;
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.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //1. 定义用户详细信息服务
    @Override
    public UserDetailsService userDetailsService(){
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("dong").password(passwordEncoder().encode("123456")).roles("admin").authorities("p1","p2").build());
        manager.createUser(User.withUsername("lang").password(passwordEncoder().encode("123456")).roles("student").authorities("p1").build());
        //或下面这样写
        //manager.createUser(new User("admin",passwordEncoder().encode("123456"), AuthorityUtils.createAuthorityList("p1","p2")));
        return manager;
    }

    //2. 密码编码器(定义密码是否加密等)
    //上面的用户信息账户和密码相当于数据库的密码,是正确的密码(接下来需要和我们输入的密码进行比对)
    // passwordEncoder.encode()  用于加密密码
    // passwordEncoder.matchs(原始密码,加密密码)对比原始密码与加密密码
    @Bean
    public PasswordEncoder passwordEncoder() {
        //加密的方式 
        return new BCryptPasswordEncoder();
    }

    //3. 安全拦截机制
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/r/**","/login-success").authenticated() //需要认证才能访问
                .antMatchers().hasRole("admin")//需要是admin角色
                .anyRequest().permitAll()//其它请求都允许
                .and()
                .formLogin() //允许基于Form表单登录验证
                .successForwardUrl("/login-success")//自定义登录成功的页面地址(可以不写)
                .and()
                .userDetailsService(userDetailsService());
        //补充一下用法
        //.antMatchers("/r/**").hasRole("ADMIN") //需要相应的角色才能访问(用户拥有角色时)
        //.anyRequest().authenticated() // 任何请求都需要认证
    }
}

WebConfig :让首页默认跳转到登录页面

package com.dong.security.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("redirect:/login");
    }
}

controller

@RestController
public class LoginController {
    //登录成功后的提示信息
    @RequestMapping(value = "/login-success" , produces = {"text/plain; charset=UTF-8"})
    public String loginSuccess(){
        return "登录成功";
    }
    
    @RequestMapping(value = "/r/r1" , produces = {"text/plain; charset=UTF-8"})
    public String r1(){
        return "访问资源r1";
    }

    @RequestMapping(value = "/r/r2" , produces = {"text/plain; charset=UTF-8"})
    public String r2(){
        return "访问资源r2";
    }
}
  1. (登录)认证后测试

运行程序访问:http://localhost:8080/ 默认跳转到http://localhost:8080/login显示security自带的登录界面。

权限-基于内存的方式实现security(三)

输入账户 dong 密码123456 显示:登录成功。

输入账户 lang 密码 123456 显示403:表示没有权限。因为lang不是admi角色而是其它角色。

没登陆前访问:/r/**会跳转到登录界面。

登录成功后访问:http://localhost:8080/r/r1 提示:访问资源r1

访问:http://localhost:8080/logout可以到退出页面(security自带)

  1. 其它方法实现认证

上面是使用这种方法将用户存入内存

   //1. 定义用户详细信息服务
    @Override
    public UserDetailsService userDetailsService(){
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("dong").password(passwordEncoder().encode("123456")).roles("admin").authorities("p1","p2").build());
        manager.createUser(User.withUsername("lang").password(passwordEncoder().encode("123456")).roles("student").authorities("p1").build());
        //或下面这样写
        //manager.createUser(new User("admin",passwordEncoder().encode("123456"), AuthorityUtils.createAuthorityList("p1","p2")));
        return manager;
    }

我们还可以使用下面这种方法替换上面的方法将用户存入内存。

 @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication() //认证信息存储到内存中
                .passwordEncoder(passwordEncoder())
                .withUser("dong").password(passwordEncoder().encode("123456")).roles("admin")
                .authorities("p1","p2");
    }

改为这种方式后:安全拦截机制不需要.and().userDetailsService(userDetailsService());

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/r/**","/login-success").authenticated() //需要认证才能访问
                .antMatchers().hasRole("admin")//需要是admin角色
                .anyRequest().permitAll()//其它请求都允许
                .and()
                .formLogin() //允许基于Form表单登录验证
                .successForwardUrl("/login-success");//自定义登录成功的页面地址(可以不写)
    }
  1. 实现授权

关键语句:antMatchers().hasAnyAuthority()

修改安全拦截机制代码如下

 @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/r/r1").hasAnyAuthority("p1")
                .antMatchers("/r/r2").hasAnyAuthority("p2")
                .antMatchers("/r/**","/login-success").authenticated() //需要认证才能访问
                .antMatchers().hasRole("admin")//需要是admin角色
                .anyRequest().permitAll()//其它请求都允许
                .and()
                .formLogin() //允许基于Form表单登录验证
                .successForwardUrl("/login-success")//自定义登录成功的页面地址(可以不写)
                .and()
                .userDetailsService(userDetailsService());
    }
  1. 授权后测试

dong拥有p1和p2权限,登录成功后能访问/r/r1和/r/r2

lang拥有p1权限,登录成功后访问/r1/r1正常返回结果,访问/r/r2报403没有权限的错误。

上一篇:Java Spring Security 5 报错:There is no PasswordEncoder mapped for the id “null”


下一篇:Spring Security 用户配置