依赖

  		 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!--页面相关包-->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.3</version>
        </dependency>

启动类

@SpringBootApplication
@EnableWebSecurity
public class SpringSecurityMain6666 {
    public static void main(String[] args) {
        SpringApplication.run(SpringSecurityMain6666.class, args);
    }
}

两种方式获取账户密码

1、配置类配置账户密码

server.port=9098

spring.application.name=cloud-spring-security-service6666
spring.security.user.name=admin
spring.security.user.password=123456

# 关闭页面缓存方便看效果
spring.thymeleaf.cache=false


2、实现 UserDetailsService 接口

实现 UserDetailsService 接口规范,可以自定义账户密码,可以从数据库或者 redis 取数据。


@Service
public class MyUserDeatilService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println(">>>>>>username="+username);
        MyUser user = MyDb.queryUserByName(username);

        return Optional.ofNullable(user)
                .map(r->{
                    System.out.println(">>>>>>>>user="+user);
                    return new User(username,new BCryptPasswordEncoder().encode(user.getPassword()),
                            // 注意这里角色是 ROLE_xxx 有前缀的哦
                            AuthorityUtils.commaSeparatedStringToAuthorityList("admin1,ROLE_role11"));
                })
                .orElseThrow(()->{
                    System.out.println(">>>>>>>Sorry,没有该用户!");
                    return new RuntimeException("Sorry,没有该用户!!");
                });
    }
}

注意:角色需要加上 ROLE_xxx 前缀,比如 role1 角色,需要写成 ROLE_role1,权限名不用直接写 admin1 即可。

3、实现配置类 WebSecurityConfigurerAdapter

SpringSecurity 所有的重要操作都在这。不同的操作可以覆写不同的方法实现


@Configuration
public class MyWebSecurityConfig2 extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private DataSource dataSource;

	// 密码加密
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }
	
 	// 将前端页面传递过来的账户密码保存到数据中
 	// 实现记住密码的功能
    @Autowired
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        return jdbcTokenRepository;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.exceptionHandling().accessDeniedPage("/no_authen.html");
        // 表示准别自定义一些跳转页面
        http.formLogin()
                // 定义自己的具体登录页面
                .loginPage("/userLogin.html")

                // 定义表单提交之后交给具体的处理 LoginController
                .loginProcessingUrl("/login")

                // 当登录成功之后跳转到哪个具体的 IndexController
                .defaultSuccessUrl("/helloIndex").permitAll()

                // 设置哪些路径可以被放行,不需要认证
                .and().authorizeRequests()
                .antMatchers("/hello","/login").permitAll()

                // 表示当前登录的人必须要有 admin 权限才可以访问 /helloIndex 路径
                // 注意 hasAuthority 只能设置单个角色或者是单个权限控制,多个要用 hasAnyAuthority()
                // .antMatchers("/helloIndex").hasAuthority("admin1")

                // 表单当前这个用户只有具备 admin1/2/3 任意一个权限就可以访问 /helloIndex
                .antMatchers("/helloIndex").hasAnyAuthority("admin1","admin2","admin3")

                // 表单需要具备 role1 角色才能够访问 /helloIndex
                // .antMatchers("/helloIndex").hasRole("role1")

                // 表单需要具备 role1/2/3 任意一个角色才能够访问 /helloIndex
                // .antMatchers(("/helloIndex")).hasAnyRole("role1","role2","role3")
                .anyRequest().authenticated()
                .and().rememberMe().tokenRepository(persistentTokenRepository())
                .tokenValiditySeconds(60) // 设置有效时长为 60s
                .userDetailsService(userDetailsService)

                // 关闭 csrf 防护
                .and().csrf().disable();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()
                .antMatchers("/resources/**");
    }

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

其中 hasAnyRole()、hasAnyAuthority() 方法时用来判断当前登录中的用户是否具备哪些权限或者角色,只有具备这些配置的权限或权限才可以登录成功,否则跳转到 no_authen.html 无权限访问页面。

注解替换 hasAnyRole()/hasAnyAuthority() 方法

使用注解来实现权限管控需要开启一个注解 @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)

@Secured 注解只能用来判断角色,如:

    @RequestMapping("/update")
    // @Secured 只能用来判断具备哪些角色,不能用来判断权限
    @Secured({"ROLE_role11","ROLE_role1"})
    public String update() {
        return "update 界面.....";
    }

当前用户需具备 ROLE_role11ROLE_role1 角色才可以访问该方法。

@PreAuthorize 注解可以替换 hasAnyRole()/hasAnyAuthority() 方法,如:

    @RequestMapping("/update")
    // @PreAuthorize("hasRole('ROLE_role12')")
    // @PreAuthorize("hasAnyRole('ROLE_role12','ROLE_role11')")
    // @PreAuthorize("hasAuthority('admin2')")
    @PreAuthorize("hasAnyAuthority('admin1','admin2')")
    // TODO @PreAuthorize("hasPermission()")
    public String update() {
        return "update 界面.....";
    }

最后提供一个 JWT 加解密的方式:

@Component
public class MyTokenManager {
    private long tokenExpiration = 24*60*60*1000;
    private String tokenSignKey = "123456";

    public String createToken(String userName) {
        return Jwts.builder().setSubject(userName)
                .setExpiration(new Date(System.currentTimeMillis() - tokenExpiration))
                .signWith(SignatureAlgorithm.HS512, tokenSignKey)
                .compressWith(CompressionCodecs.GZIP)
                .compact();
    }

    public String getTokenSignKey() {
        return Jwts.parser().setSigningKey(tokenSignKey)
                .parseClaimsJws(tokenSignKey)
                .getBody()
                .getSubject();
    }
}

版权声明:本文为qq_35971258原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_35971258/article/details/126793879