Spring Boot 学习之路之 Spring Security(一)

        Spring Security是一种基于 Spring AOP 和 Servlet 过滤器的企业级安全框架,由 spring 官方推出,提供全面的安全性解决方案,它对软件系统中的认证、授权、加密等功能进行封装,并在Spring Boot 技术推出以后,配置方面做了很大的简化。

        Spring Security 本质是一个过滤链条,其中有比较重要的三条过滤器:

        1:FilterSecurityInterceptor:是一个方法级的权限过滤器,基本位于过滤器链的最底部。

        2:ExceptionTranslationFilter:是个异常过滤器,用来处理在认证授权过程中抛出的异常。

        3:UsernamePasswordAuthenticationFilter:对/login的post请求做拦截,校验表单中的用户名和密码。

        过滤器加载流程:

        使用SpringSecurity配置过滤器(DelegatingFilterProxy),在doFilter方法里使用初始化方法,得到一个叫FilterChainProxy的过滤器,在FilterChainProxy过滤器中得到所有的过滤器并加载到过滤链中,在SecurityFilterChain过滤器中调用getFilters方法完成加载。

        实现Security需要用到两个比较重要的接口:

        1、UserDetailsService接口:什么都没有配置的时候,登录账号和密码是由Sercurity定义生成,但当我们需要实际的账号和密码时,就需要通过自定义逻辑控制认证逻辑。

        2、PasswordEncoder接口:数据加密接口,其中BCryptPasswordEncoder是Security官方推荐的密码解析器。表示验证从存储中获取的编码密码与编码后提交的原始密码是否匹配,如果密码匹配,则返回 true,否则返回 false。

        准备工作(一)构建项目:

        

 

 

        下一步 finish后,创建一个简单的controller以及yal配置,完成访问测试:

server:
  port: 8089

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/wanxi?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8&useSSL=false
    username: root
    password: 19980801

         启动成功后会,访问配置的路径,会看到这样一个页面,此登录页面是security自带的,用户名是"user",密码在你启动时会给出(在下一张图展示)"e8ea2c58-6989-4895-bf3d-6208f0ac8c98"

 

         完成用户名及密码的输入后,便能成功访问到想要的效果:

         至此,项目创建完成。

        1、创建至少2个controller,以便测试:

@RestController
public class SecurityController {

    @RequestMapping("/hello")
    public String hello() {
        return "hello springboot !";
    }

    @RequestMapping("/user")
    public String user() {
        return "成功访问user资源。。。";
    }
}

        2、创建一个自定义的配置类,配置资源认证规则:

@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 第一步,当访问的是hello资源时不需要进行验证。
        http.authorizeRequests()
                .antMatchers("/hello").permitAll() // 放行指定的资源
                .anyRequest().authenticated()
                .and()
                .formLogin();
    }
}

        配置完成后,再次访问时即可发现,访问hello资源,无需做额外操作,但是访问的不是hello资源时,则会给到一个登录页面,登录成功才能完成资源访问。

        如果觉得每次需要复制密码登录麻烦,可以去yml里面配置登录用的用户名和密码:

spring:
  security:
    user:
      name: wx
      password: 123456

        至此,就完成了Security两大部分之一的Authentication:认证。

        3、接下来,为controller添加访问权限:

@RestController
public class SecurityController {

    @RequestMapping("/hello")
    public String hello() {
        return "hello springboot !";
    }

    @PreAuthorize("hasAuthority('wx:user')")
    @RequestMapping("/user")
    public String user() {
        return "成功访问user资源。。。";
    }

    @PreAuthorize("hasAuthority('wx:other')")
    @RequestMapping("/other")
    public String other() {
        return "成功访问other资源。。。";
    }
}

        4、创建一个userEntity,并实现UserDetails接口:

public class UserEntity implements UserDetails {
    private long id;
    private String username;
    private String password;

    public void setAuthorities(Set<? extends GrantedAuthority> authorities) {
        this.authorities = authorities;
    }

    private Set<? extends GrantedAuthority> authorities =  new HashSet<>();

    public UserEntity() {
    }

    public UserEntity(long id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public void setName(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String getUsername() {
        return this.username;
    }

    @Override
    public String getPassword() {
        return this.password;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return this.authorities;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    @Override
    public String toString() {
        return "UserEntity{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

        5、创建一个permission实体类,并实现GrantedAuthority接口:

public class Permission implements GrantedAuthority {
    private long id;
    private String value;

    @Override
    public String getAuthority() {
        return this.value;
    }

    public Permission() {
    }

    public Permission(long id, String value) {
        this.id = id;
        this.value = value;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "Permission{" +
                "id=" + id +
                ", value='" + value + '\'' +
                '}';
    }
}

        6、创建myUserDetailsService(该名字最好和UserDetailsService区分开来),因为需要实现UserDetailsService接口:

@Service(value = "myUserDetailsService")
public class MyUserDetailsService implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        UserEntity userEntity = new UserEntity();
        userEntity.setName("wx");
        // 这里密码必须使用加密后的密码,加密规则对应下文配置里的加密方法(我这里用的是BCrypt),password:123456
        userEntity.setPassword("$2a$10$y/j0iaqkWkfgsa6OQtHgieT8Mg5xou0TLkiZ/8F8OzcuHBzSpukxm");

        Permission permission = new Permission();
        //添加权限允许访问规则
        permission.setValue("wx:user");

        Set<Permission> permissionSet = new HashSet<>();
        permissionSet.add(permission);

        userEntity.setAuthorities(permissionSet);

        return userEntity;
    }
}

        7、修改 MySecurityConfig 配置类:

//@Configuration

//此注解是为controller里的方法添加约束,不至于可以随意访问
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    MyUserDetailsService myUserDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 第一步,当访问的是hello资源时不需要进行验证。
        http.authorizeRequests()
                .antMatchers("/hello").permitAll() // 放行指定的资源
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .and()
                .userDetailsService(myUserDetailsService);
    }

    /**
     * 为密码进行加密,这个得有
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

        8、启动入口函数、访问资源:

        因为对hello资源放行了,因此可以直接访问资源 :

        然后user资源添加了wx:user的权限,但是为当前用户开放了此权限,因此登录认证后可以访问资源(访问路径是:http:localhost/8089/user, login路径是自动跳转的):

 

        接下来是加了wx:other权限的other资源,此资源配置了权限,但是并没有对当前用户开放,因此此用户登录后是无法访问该资源的:

         至此,登录认证和授权就算成功完成,以上代码亲测有效。

下一篇:Spring Security 加入 mybatis:http://t.csdn.cn/CmOAF​​​​​​​

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值