spring security扩展点入门示例

36 篇文章 0 订阅
16 篇文章 0 订阅

登录认证自定义

  1. 创建密码加密器并放到spring容器中

    package com.snail.learn.security.config;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    @Configuration
    public class SecurityConfig {
        @Bean
        public PasswordEncoder getPasswordEncoder(){
            return new BCryptPasswordEncoder();
        }
    }
    
  2. 重写UserDetailService

    package com.snail.learn.security.service;
    
    import cn.hutool.core.util.StrUtil;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.authority.AuthorityUtils;
    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.core.userdetails.UsernameNotFoundException;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.stereotype.Service;
    
    @Service
    public class UserDetailServiceImpl implements UserDetailsService {
    
        @Autowired
        private PasswordEncoder passwordEncoder;
    
        @Override
        public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
            // 登录校验逻辑(实际可以从数据库中查询)
            if(!StrUtil.equals("snail",userName)){
                throw new UsernameNotFoundException("用户名不存在!");
            }
            String pwd = passwordEncoder.encode("123");
            // 构造用户信息(获取有权限的资源清单)
            return new User(userName,pwd,
                    AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal"));
        }
    }
    
  3. 测试使用

    1. 重启系统,则次登录,使用的账号、密码即为我们自定义中的账号和密码

登录页面自定义

  1. 编写登录页面

    <!-- 登录处理请求必须为/login  用户名、密码必须为:username、password -->
    form method="post" action="/login">
        <input type="text" required="required" placeholder="用户名" name="username"></input>
    	<input type="password" required="required" placeholder="密码" name="password"></input>
    	<button class="but" type="submit">登录</button>
    </form>
    
  2. 修改配置

    package com.snail.learn.security.config;
    
    import org.springframework.context.annotation.Bean;
    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 org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .antMatchers("/login.html","/**/*.css").permitAll() //
                    .anyRequest().authenticated()
                // 资源拦截,并放行不需要认证的资源,如:登录页面,静态资源等
                    .and()
                    .formLogin().loginPage("/login.html").loginProcessingUrl("/login")
                    .successForwardUrl("/test")
                // 修改登录页面的配置:loginPage 指定登录的页面,loginProcessingUrl指定处理登录请求的url,必须也登录页面中指定的一样,successForwardUrl 指定登录成功后的跳转页面。
                    .and()
                    .csrf().disable();
               // 关闭csrf(暂时关闭)
        }
    
        @Bean
        public PasswordEncoder getPasswordEncoder(){
            return new BCryptPasswordEncoder();
        }
    }
    
  3. 测试使用: 再次重启后可以进入到自定义的登录页面。

  4. 登录页面的自定义内容还有

    .failureForwardUrl("/error") // 登录失败的跳转页面
        .usernameParameter("userName") // 登录页面中用户名的参数名,需要与登录页面的一致
        .passwordParameter("pwd") // 登录页面中密码的参数名,需要与登录页面的一致
        .successHandler() // 自定义登录成功处理类
        .failureHandler() // 自定义登录失败处理类
    .and()
    .exceptionHandling()
        .accessDeniedHandler(myAccessDeniedHandler) // 自定义异常处理类(无权限403)
    

授权

​ .anyRequest().authenticated() 必须在授权配置的最后面。

​ antMatchers: ant表达式的匹配器,另外也可以指定请求的类型(默认所有的请求)

?:匹配单个字符
*:匹配0或多个字符
**:匹配0或多个目录

示例:
/a/* :匹配 /a/ 下的所有路径,不递归,如: /a/b,/a/c,但不包括/a/b/c
/a/**:匹配 /a/ 下所有路径,递归,如 :/a/b,/a/b/c,/a/b/c/d
/a/a?c:匹配/a/ 下路径中a开头,c结尾,中间按含任意字符的路径,如:/a/adc

​ regexMatchers : 正则表达式的匹配器 ,另外也可以指定请求的类型(默认所有的请求)

​ .mvcMatchers().servletPath() : mvcMatchers 中可以配置servletPath,如 有请求/xxx/test,则可以配置成.mvcMatchers(“/test”).servletPath("/xxx")

​ hasAuthority(“admin”) // 需要有admin的权限 才能访问

​ hasAnyAuthority(“admin”,“sysadmin”) //需要有 admin或 sysadmin的权限才能访问

​ hasRole(“admin”) / hasAnyRole(“admin”,“sysadmin”) // 需要有“ROLE_admin”的权限 / “ROLE_admin”或“ROLE_sysadmin” …

​ hasRole中的值不能以“ROLE_”开头.

​ .access(“hasRole(‘admin’)”) // 与hasRole(“admin”) 一样

.hasIpAddress(“127.0.0.1”) // 只能本机访问

​ .access("@myServiceImpl.hasPermission(request,authentication)") // myServiceImpl 为自定义的权限控制类(不需继承任何类),hasPermission方法返回boolean类型,为true时表示有权限,false时表示无权限

基于注解的访问控制

​ 允许的注解:@PreAuthorize, @PostAuthorize, @Secured( 相当于hasRole ,且权限必须以“ROLE_”开头)

​ 对应注解需要启用的话,需要在配置类中增加@EnableGlobalMethodSecurity注解,并分别设置securedEnabled、prePostEnabled为true.

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //....
}


@RestController
public class TestController {
    @RequestMapping("/test")
    @Secured("ROLE_admin")
    public String test(){
        return "test";
    }
}

记住登录

其底层实现是依赖于数据库的,所以需要集成数据库。
依赖
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.3</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>
配置
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://192.168.3.18/security?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
# 创建对应的数据库,不需要创建表    
@Autowired
private DataSource dataSource;

@Autowired
private PersistentTokenRepository persistentTokenRepository;

@Autowired
private UserDetailServiceImpl userDetailService;

@Bean
public PersistentTokenRepository persistentTokenRepository(){
    JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
    jdbcTokenRepository.setDataSource(dataSource);
    jdbcTokenRepository.setCreateTableOnStartup(true);
    return jdbcTokenRepository;
}

 @Override
protected void configure(HttpSecurity http) throws Exception {
    http.rememberMe()
        .tokenRepository(persistentTokenRepository)
        .tokenValiditySeconds(60) // 设置有效时间为60秒,默认为2周。
        .userDetailsService(userDetailService)
}      
<form method="post" action="/login">
    <input type="text" required="required" placeholder="用户名" name="username"></input>
	<input type="password" required="required" placeholder="密码" name="password"></input>
	<input type="checkbox"  name="remember-me" value="true"></input> <!-- name必须是“remember-me”  -->
	<button class="but" type="submit">登录</button>
</form>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蜗牛_snail

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值