[英]How to configure Spring security Oauth 2.0 with dynamic URL matchers configuration?
[英]Spring boot security configuration with both dynamic matchers and roles
我正在寻找一种解决方案,我可以使用 spring 引导安全性来管理用户访问,具体如下:
每个用户都绑定到一个组列表。 组是动态的,这意味着可以随时向用户分配/删除新组。
有动态创建的实体。 例如,让我们将它们视为某个博客网站上的“文章”:) 与用户类似,这些“文章”对可以访问它的组列表感到厌烦。
总之:一个在运行时知道组和访问列表的系统。
我对 spring 安全性了解不多,所以我在 web 上寻找一些答案,但找不到任何东西。 所有片段都基于 static antMatchers 和角色,如下所示:
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/something_else_instead_of_this").hasRole("ROLE_and_instead_of_this_static_role");
}
(...)
}
有什么方法可以创建您自己的自定义身份验证器或类似的东西,它基于(1) URL 会找到“文章”,因此允许访问的组,以及(2)用户登录,因此分配的组=>将确定我是否可以继续处理请求或立即返回 401;)
在此先感谢您的帮助!
我认为您不能仅在WebSecurityConfigurerAdapter
中执行此操作,但这里有一个类似的设置,它利用了 Spring 安全性并演示了如何将访问检查添加到 controller 方法。
附加pom.xml
依赖项:
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
...
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
...
(后者仅当您使用 Thymeleaf 时。)
WebSecurityConfigurerAdapter
:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@NoArgsConstructor @Log4j2
public class WebSecurityConfigurerImpl extends WebSecurityConfigurerAdapter {
@Autowired private UserDetailsService userDetailsService;
@Autowired private PasswordEncoder passwordEncoder;
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder);
}
@Override
public void configure(WebSecurity web) {
web.ignoring()
.antMatchers("/css/**", "/js/**", "/images/**",
"/webjars/**", "/webjarsjs");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().anyRequest().permitAll()
.and().formLogin().loginPage("/login").permitAll()
.and().logout().permitAll();
}
}
在 web MVC @Controller
中,任何人都可以阅读文章(无论是否登录):
@RequestMapping(method = { GET }, value = { "/article/{slug}/" })
@PreAuthorize("permitAll()")
public String article(Model model, @PathVariable String slug) {
...
}
但只有作者可以使用预览功能:
@RequestMapping(method = { GET }, value = { "/preview/" })
@PreAuthorize("hasAuthority('AUTHOR')")
public String preview(Model model) {
...
}
@RequestMapping(method = { POST }, value = { "/preview/" })
@PreAuthorize("hasAuthority('AUTHOR')")
public String previewPOST(Model model,
Principal principal, HttpSession session,
HttpServletRequest request,
@Valid PreviewForm form, BindingResult result) {
...
}
Thymeleaf 模板也支持这一点,如果用户是 AUTHOR,则有条件地显示菜单。
<li th:ref="navbar-item" sec:authorize="hasAuthority('AUTHOR')">
<button th:text="'Author'"/>
<ul th:ref="navbar-dropdown">
<li><a th:text="'Preview'" th:href="@{/preview/}"/></li>
</ul>
</li>
并处理登录/注销菜单以演示其他可用的安全谓词:
<li th:ref="navbar-item" sec:authorize="!isAuthenticated()">
<a th:text="'Login'" th:href="@{/login}"/>
</li>
<li th:ref="navbar-item" sec:authorize="isAuthenticated()">
<button sec:authentication="name"/>
<ul th:ref="navbar-dropdown">
<li><a th:text="'Change Password'" th:href="@{/password}"/></\
li>
<li><a th:text="'Logout'" th:href="@{/logout}"/></li>
</ul>
</li>
(rest 是实现细节,可能有助于说明,但不一定特定于您的问题。具体来说,我建议您的逻辑适用于“动态”组。)
UserDetailsService
ervice 实现依赖于JpaRepository
实现并设置用户的授权:
@Service
@NoArgsConstructor @ToString @Log4j2
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired private CredentialRepository credentialRepository;
@Autowired private AuthorRepository authorRepository;
@Autowired private SubscriberRepository subscriberRepository;
@Override
@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = null;
Optional<Credential> credential =
credentialRepository.findById(username);
if (credential.isPresent()) {
HashSet<GrantedAuthority> set = new HashSet<>();
subscriberRepository.findById(username)
.ifPresent(t -> set.add(new SimpleGrantedAuthority("SUBSCRIBER")));
authorRepository.findById(username)
.ifPresent(t -> set.add(new SimpleGrantedAuthority("AUTHOR")));
user = new User(username, credential.get().getPassword(), set);
} else {
throw new UsernameNotFoundException(username);
}
return user;
}
}
还有一个JpaRepository
的例子:
@Repository
@Transactional(readOnly = true)
public interface AuthorRepository extends JpaRepository<Author,String> {
public Optional<Author> findBySlug(String slug);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.