SpringSecurity简单搭建

霄
2023-01-21 / 0 评论 / 89 阅读 / 正在检测是否收录...

- 添加 Spring Security 依赖

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

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

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

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

  • UserDetails

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

public interface UserDetails extends Serializable {

    //返回分配给用户的角色列表
    Collection<? extends GrantedAuthority> 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<? extends GrantedAuthority> authorities;

    User(String id, String account, String password, Collection<? extends GrantedAuthority> authorities) {
        this.id = id;
        this.account = account;
        this.password = password;
        this.authorities = authorities;
    }

    //返回分配给用户的角色列表
    @Override
    public Collection<? extends GrantedAuthority> 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;
    }
}
  • 继承


Created by Yuicon on 2017/5/14.


https://segmentfault.com/u/yuicon
*/
@Service
public 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<GrantedAuthority> mapToGrantedAuthorities(List<String> 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();
}
}

使用 @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<User> getUsers() {
return repository.findAll();
}
}

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

扫描二维码,在手机上阅读!
47

评论

博主关闭了当前页面的评论