博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring Boot中使用 Spring Security 构建权限系统
阅读量:5962 次
发布时间:2019-06-19

本文共 7352 字,大约阅读时间需要 24 分钟。

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

权限控制是非常常见的功能,在各种后台管理里权限控制更是重中之重.在Spring Boot中使用 Spring Security 构建权限系统是非常轻松和简单的.下面我们就来快速入门 Spring Security .在开始前我们需要一对多关系的用户角色类,一个restful的controller.

- 添加 Spring Security 依赖

首先我默认大家都已经了解 Spring Boot 了,在 Spring Boot 项目中添加依赖是非常简单的.把对应的

spring-boot-starter-*** 加到pom.xml 文件中就行了

org.springframework.boot
spring-boot-starter-security

- 配置 Spring Security

简单的使用 Spring Security 只要配置三个类就完成了,分别是:

  • UserDetails

这个接口中规定了用户的几个必须要有的方法

public interface UserDetails extends Serializable {    //返回分配给用户的角色列表    Collection
getAuthorities(); //返回密码 String getPassword(); //返回帐号 String getUsername(); // 账户是否未过期 boolean isAccountNonExpired(); // 账户是否未锁定 boolean isAccountNonLocked(); // 密码是否未过期 boolean isCredentialsNonExpired(); // 账户是否激活 boolean isEnabled();}
  • UserDetailsService

这个接口只有一个方法 loadUserByUsername,是提供一种用 用户名 查询用户并返回的方法。

public interface UserDetailsService {    UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;}
  • WebSecurityConfigurerAdapter

这个内容很多,就不贴代码了,大家可以自己去看.

我们创建三个类分别继承上述三个接口

  • 此 User 类不是我们的数据库里的用户类,是用来安全服务的.
/** * Created by Yuicon on 2017/5/14. * https://segmentfault.com/u/yuicon */public class User implements UserDetails {    private final String id;    //帐号,这里是我数据库里的字段    private final String account;    //密码    private final String password;    //角色集合    private final Collection
authorities; User(String id, String account, String password, Collection
authorities) { this.id = id; this.account = account; this.password = password; this.authorities = authorities; } //返回分配给用户的角色列表 @Override public Collection
getAuthorities() { return authorities; } @JsonIgnore public String getId() { return id; } @JsonIgnore @Override public String getPassword() { return password; } //虽然我数据库里的字段是 `account` ,这里还是要写成 `getUsername()`,因为是继承的接口 @Override public String getUsername() { return account; } // 账户是否未过期 @JsonIgnore @Override public boolean isAccountNonExpired() { return true; } // 账户是否未锁定 @JsonIgnore @Override public boolean isAccountNonLocked() { return true; } // 密码是否未过期 @JsonIgnore @Override public boolean isCredentialsNonExpired() { return true; } // 账户是否激活 @JsonIgnore @Override public boolean isEnabled() { return true; }}
  • 继承 UserDetailsService
/** * Created by Yuicon on 2017/5/14. * https://segmentfault.com/u/yuicon */@Servicepublic class UserDetailsServiceImpl implements UserDetailsService {        // jpa    @Autowired    private UserRepository userRepository;    /**     * 提供一种从用户名可以查到用户并返回的方法     * @param account 帐号     * @return UserDetails     * @throws UsernameNotFoundException     */    @Override    public UserDetails loadUserByUsername(String account) throws UsernameNotFoundException {        // 这里是数据库里的用户类        User user = userRepository.findByAccount(account);        if (user == null) {            throw new UsernameNotFoundException(String.format("没有该用户 '%s'.", account));        } else {            //这里返回上面继承了 UserDetails  接口的用户类,为了简单我们写个工厂类            return UserFactory.create(user);        }    }}
  • UserDetails 工厂类
/** * Created by Yuicon on 2017/5/14. * https://segmentfault.com/u/yuicon */final class UserFactory {    private UserFactory() {    }    static User create(User user) {        return new User(                user.getId(),                user.getAccount(),                user.getPassword(),            mapToGrantedAuthorities(user.getRoles().stream().map(Role::getName).collect(Collectors.toList()))        );    }        //将与用户类一对多的角色类的名称集合转换为 GrantedAuthority 集合    private static List
mapToGrantedAuthorities(List
authorities) { return authorities.stream() .map(SimpleGrantedAuthority::new) .collect(Collectors.toList()); }}
  • 重点, 继承 WebSecurityConfigurerAdapter 类
/** * Created by Yuicon on 2017/5/14. * https://segmentfault.com/u/yuicon */@Configuration@EnableWebSecurity@EnableGlobalMethodSecurity(prePostEnabled = true)public class WebSecurityConfig extends WebSecurityConfigurerAdapter {    // Spring会自动寻找实现接口的类注入,会找到我们的 UserDetailsServiceImpl  类    @Autowired    private UserDetailsService userDetailsService;    @Autowired    public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {        authenticationManagerBuilder                // 设置UserDetailsService                .userDetailsService(this.userDetailsService)                // 使用BCrypt进行密码的hash                .passwordEncoder(passwordEncoder());    }    // 装载BCrypt密码编码器    @Bean    public PasswordEncoder passwordEncoder() {        return new BCryptPasswordEncoder();    }    //允许跨域    @Bean    public WebMvcConfigurer corsConfigurer() {        return new WebMvcConfigurerAdapter() {            @Override            public void addCorsMappings(CorsRegistry registry) {                registry.addMapping("/**").allowedOrigins("*")                        .allowedMethods("GET", "HEAD", "POST","PUT", "DELETE", "OPTIONS")                        .allowCredentials(false).maxAge(3600);            }        };    }    @Override    protected void configure(HttpSecurity httpSecurity) throws Exception {        httpSecurity                // 取消csrf                .csrf().disable()                // 基于token,所以不需要session                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()                .authorizeRequests()                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()                // 允许对于网站静态资源的无授权访问                .antMatchers(                        HttpMethod.GET,                        "/",                        "/*.html",                        "/favicon.ico",                        "/**/*.html",                        "/**/*.css",                        "/**/*.js",                        "/webjars/**",                        "/swagger-resources/**",                        "/*/api-docs"                ).permitAll()                // 对于获取token的rest api要允许匿名访问                .antMatchers("/auth/**").permitAll()                // 除上面外的所有请求全部需要鉴权认证                .anyRequest().authenticated();        // 禁用缓存        httpSecurity.headers().cacheControl();    }}

- 控制权限到 controller

使用 @PreAuthorize("hasRole('ADMIN')") 注解就可以了

/** * 在 @PreAuthorize 中我们可以利用内建的 SPEL 表达式:比如 'hasRole()' 来决定哪些用户有权访问。 * 需注意的一点是 hasRole 表达式认为每个角色名字前都有一个前缀 'ROLE_'。所以这里的 'ADMIN' 其实在 * 数据库中存储的是 'ROLE_ADMIN' 。这个 @PreAuthorize 可以修饰Controller也可修饰Controller中的方法。 **/@RestController@RequestMapping("/users")@PreAuthorize("hasRole('USER')") //有ROLE_USER权限的用户可以访问public class UserController {   @Autowired    private UserRepository repository;    @PreAuthorize("hasRole('ADMIN')")//有ROLE_ADMIN权限的用户可以访问    @RequestMapping(method = RequestMethod.GET)    public List
getUsers() { return repository.findAll(); }}

- 结语

Spring Boot中 Spring Security 的入门非常简单,很快我们就能有一个满足大部分需求的权限系统了.而配合 Spring Security 的好搭档就是 JWT 了,两者的集成文章网络上也很多,大家可以自行集成.因为篇幅原因有不少代码省略了,需要的可以参考

转载地址:http://prjax.baihongyu.com/

你可能感兴趣的文章
poj 1131进制转换
查看>>
android:layout_weight属性详解
查看>>
java随机生成字符串和校验
查看>>
[编程] TCP协议概述
查看>>
HashMap 原理?jdk1.7 与 1.8区别
查看>>
阿里云 Debian Linux 布署记录
查看>>
了解JavaScript 数组对象及其方法
查看>>
设置Tomcat的UTF-8编码
查看>>
Java基础5:抽象类和接口
查看>>
方法 属性 构造方法和包
查看>>
2.db2数据库基础篇2
查看>>
BZOJ-2140: 稳定婚姻 (tarjan强连通分量)
查看>>
BZOJ-1433: [ZJOI2009]假期的宿舍 (网络流最大流经典问题)
查看>>
Linux平台Cpu使用率的计算
查看>>
Ackermann Steering System
查看>>
MS CRM 2011的自定义和开发(11)——插件(plugin)开发(一)
查看>>
C#中静态和非静态的区别
查看>>
SQL SERVER 修改数据库名称(包括 db.mdf 名称的修改)
查看>>
详解定位与定位应用
查看>>
fiddler(二)、配置抓取https协议
查看>>