- pxm.xml 引用开发包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
- 创建User和Auth实体类 user实现UserDetails接口 Auth实现GrantedAuthority接口
package com.cloud.consumer.config.security.model;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.List;
public class User implements UserDetails {
private String userName;
private String password;
private List<Auth> list;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void setPassword(String password) {
this.password = password;
}
public List<Auth> getList() {
return list;
}
public void setList(List<Auth> list) {
this.list = list;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.list;
}
@Override
public String getPassword() {
return this.password;
}
@Override
public String getUsername() {
return this.getUserName();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
package com.cloud.consumer.config.security.model;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
@Data
public class Auth implements GrantedAuthority {
public Auth(String authority){
this.authority = authority;
}
private String authority;
@Override
public String getAuthority() {
return this.authority;
}
}
- 创建 SecurityConfig 配置文件
package com.cloud.consumer.config.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsServiceImpl userDetailsService;
private final AuthorizationTokenFilter authenticationTokenFilter;
public SecurityConfig(AuthorizationTokenFilter authenticationTokenFilter, UserDetailsServiceImpl userDetailsService) {
this.authenticationTokenFilter = authenticationTokenFilter;
this.userDetailsService = userDetailsService;
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.passwordEncoder(new BCryptPasswordEncoder())
.withUser("admin")
.password(new BCryptPasswordEncoder().encode("123456"))
.roles("ROOT");
auth.userDetailsService(userDetailsService).passwordEncoder(NoOpPasswordEncoder.getInstance());
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
http.authorizeRequests()
.antMatchers("/actuator/**").hasRole("ROOT")
.and().httpBasic();
http.authorizeRequests()
.antMatchers("/user/**").hasAuthority("user")
.antMatchers("/admin/**").hasAuthority("admin")
.antMatchers("/authenticated/**").authenticated()
.antMatchers("/login", "/getConsumer","/my/test3").permitAll()
.anyRequest().authenticated()
.and()
.csrf().disable();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
- 自定义实现UsernamePasswordAuthenticationFilter过滤器
package com.cloud.consumer.config.security;
import com.cloud.consumer.config.security.model.User;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class AuthorizationTokenFilter extends OncePerRequestFilter {
private final RedisTemplate redisTemplate;
public AuthorizationTokenFilter(@Qualifier("redisTemplateJdk") RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String authorization = request.getHeader("Authorization");
if (StringUtils.isNotEmpty(authorization) && SecurityContextHolder.getContext().getAuthentication() == null) {
Object object = redisTemplate.opsForValue().get(authorization);
if (object != null) {
User user = (User) object;
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(user, null,user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
chain.doFilter(request, response);
}
}
- 创建UserDetailsServiceImpl类
package com.cloud.consumer.config.security;
import com.cloud.consumer.config.security.model.Auth;
import com.cloud.consumer.config.security.model.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
@Override
public User loadUserByUsername(String userName) throws UsernameNotFoundException {
User user = new User();
user.setUserName(userName);
user.setPassword("123456");
List<Auth> list = new ArrayList<>();
list.add(new Auth("admin"));
user.setList(list);
return user;
}
}
- 登录
@PostMapping("/login")
public AjaxResult login(@NotNull(message = "用户名不能为null") String userName, @NotNull(message = "密码不能为null") String password){
User user = userDetailsService.loadUserByUsername(userName);
if (StringUtils.equals(user.getPassword(),password)) {
String token = UUID.randomUUID().toString().replaceAll("-", "");
redisTemplate.opsForValue().set(token,user);
AjaxResult ajaxResult = AjaxResult.successData(token);
return ajaxResult;
} else {
return AjaxResult.error("密码错误");
}
}
- 测试controller
@GetMapping("/admin/test1")
public AjaxResult test1() {
return AjaxResult.success("test1");
}
@GetMapping("/user/test2")
public AjaxResult test2() {
return AjaxResult.success("test2");
}
@GetMapping("/testPer1")
@PreAuthorize("hasAnyAuthority('member')")
public AjaxResult testPer1() {
return AjaxResult.success("test3");
}
@GetMapping("/testPer2")
@PreAuthorize("hasAnyAuthority('admin')")
public AjaxResult testPer2() {
return AjaxResult.success("test4");
}
记录问题
1. @PreAuthorize 注解无效
@EnableGlobalMethodSecurity(prePostEnabled = true) 是否开启
@PreAuthorize 是基于aop实现,只能注解在public方法上