本文在Spring Boot + Spring Security添加记住我功能 的基础上进行修改
- 在登录的时候,在UserDetailService中认证并授权,修改UserDetailService
@Configuration
public class UserDetailService implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 模拟一个用户,替代数据库获取逻辑
MyUser user = new MyUser();
user.setUserName(username);
user.setPassword(this.passwordEncoder.encode("123456"));
// 输出加密后的密码
System.out.println(user.getPassword());
//授权 真正的应用中会根据数据中的查询得知
List<GrantedAuthority> authorities = new ArrayList<>();
if (StringUtils.equalsIgnoreCase("admin", username)) {
authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
} else {
authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("test");
}
return new User(username, user.getPassword(), user.isEnabled(),
user.isAccountNonExpired(), user.isCredentialsNonExpired(),
user.isAccountNonLocked(), authorities);
}
}
- 新建自定义权限辅助类:
@Component
public class MyAuthenticationAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("很抱歉,您没有该访问权限");
}
}
- 开启权限注解并配置权限辅助类:
@Component
@EnableGlobalMethodSecurity(prePostEnabled = true) // 开启权限注解
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyAuthenticationFailureHandler authenticationFailureHandler;
@Autowired
private MyAuthenticationSuccessHandler authenticationSuccessHandler;
@Autowired
private ValidateCodeFilter validateCodeFilter;
@Autowired
private UserDetailService userDetailService;
@Autowired
private DataSource dataSource;
@Autowired
private MyAuthenticationAccessDeniedHandler myAuthenticationAccessDeniedHandler;
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
jdbcTokenRepository.setCreateTableOnStartup(false);
return jdbcTokenRepository;
}
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加验证码校验过滤器
.exceptionHandling()
.accessDeniedHandler(myAuthenticationAccessDeniedHandler) // 配置辅助类
.and()
.formLogin() // 表单登录
// http.httpBasic() // HTTP Basic
.loginPage("/authentication/require") // 登录跳转 URL
.loginProcessingUrl("/login") // 处理表单登录 URL
.failureHandler(authenticationFailureHandler) // 处理登录失败
.successHandler(authenticationSuccessHandler)
.and()
.rememberMe() // 启用rememberMe
.tokenRepository(persistentTokenRepository()) // 配置 token 持久化仓库
.tokenValiditySeconds(3600) // remember 过期时间,单为秒
.userDetailsService(userDetailService) // 处理自动登录逻辑
.and()
.authorizeRequests() // 授权配置
.antMatchers("/authentication/require",
"/login.html",
"/code/image").permitAll() // 无需认证的请求路径
.anyRequest() // 所有请求
.authenticated() // 都需要认证
.and().csrf().disable();
}
}
- 修改IndexController:
@RestController
public class IndexController {
@GetMapping("index")
public Object index(){
return SecurityContextHolder.getContext().getAuthentication();
}
@GetMapping("/auth/admin")
@PreAuthorize("hasAuthority('admin')") // 权限控制注解①
public String authenticationTest() {
return "您拥有admin权限,可以查看";
}
}
- 测试:
启动项目:访问http://localhost:8005/login.html ,填写用户名user密码123456,提示如下
访问http://localhost:8005/auth/admin 提示如下:
使用admin密码123456登录 提示如下:
访问http://localhost:8005/auth/admin 提示如下:
注:
①权限控制注解有:
1.Spring Security自带的@Secured注解;
开启注解:@EnableGlobalMethodSecurity(securedEnabled = true)
@Secured("ROLE_ADMIN") // 或者({"ROLE_ADMIN","ROLE_USER"})
public void test(){
...
}
2.JSR-250的@RolesAllowed注解;
@EnableGlobalMethodSecurity(jsr250Enabled = true)
@RolesAllowed("ROLE_ADMIN")
public void test(){
...
}
3.表达式驱动的注解,包括@PreAuthorize、@PostAuthorize、@PreFilter和 @PostFilter
开启注解: @EnableGlobalMethodSecurity(prePostEnabled = true)
//该注解用于方法前验证权限,下方是:限制非VIP用户提交blog的note字段字数不得超过1000字
//#form部分直接引用了方法中的同名参数。这使得Spring Security能够检查传入方法的参数,并将这些参数用于认证决策的制定
@PreAuthorize("hasRole('ROLE_ADMIN') and #form.note.length() <= 1000 or hasRole('ROLE_VIP')")
public void writeBlog(Form form){
...
}
或者:
//方法后调用权限验证,校验方法返回值 用户名是否正确
//Spring Security在SpEL中提供了名为returnObject 的变量。在这里方法返回一个User对象,所以这个表达式可以直接访问user对象中的userName属性。
@PreAuthorize("hasRole(ROLE_USER)")
@PostAuthorize("returnObject.user.userName == principal.username")
public User getUserById(long id){
...
本文代码运行正常
本文源代码:https://github.com/ttdys/springboot/tree/master/springboot_security/05_role_permission
来源:oschina
链接:https://my.oschina.net/u/4517769/blog/4337152