我认为您不能仅在 中执行此操作,WebSecurityConfigurerAdapter
但这里有一个类似的设置,它利用了 Spring Security 并演示了如何将访问检查添加到控制器方法。
附加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>
(其余的是可能有助于说明但不一定特定于您的问题的实现细节。具体来说,我建议这是您的逻辑适用于“动态”组的地方。)
UserDetailsService
实现依赖于实现并设置用户的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);
}