准备
依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.13</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
</dependencies>
用户实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String username;
private String password;
}
controller接口
@RestController
@RequestMapping("/user")
public class controller {
@Autowired
private LoginService loginService;
@PostMapping("/login")
public String login(@RequestBody User userLogin){
String token = loginService.login(userLogin);
return token;
}
@PostMapping("/hello")
@PreAuthorize("hasAuthority('user')")//这里添加访问该接口需要的角色为 ‘user’
public String hello(){
return "Hello";
}
}
集成
首先实现两个接口
- UserDetailsService–springsecurity默认有认证的账号密码,我们不使用它自带的,实现这个接口重写它的方法用于获取我们真正的用户数据
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (username == null){
throw new UsernameNotFoundException("用户不存在");
}
User user=new User();
user.setUsername("admin");
user.setPassword("$2a$10$iLLMvl6E9t7qDYexmu65VOM.tVgGwp5wHh5hSG4aC7rYuRoA6I//m");
List<String> list =new ArrayList<String>(Arrays.asList("user"));
LoginUser loginUser = new LoginUser(user,list);
return loginUser;
}
}
- UserDetails–spring认证需要的对象,实现这个方法加入我们自己的逻辑
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoginUser implements UserDetails {
private User user;
private List<String> permissions;
@JSONField(serialize = false)
private List<SimpleGrantedAuthority> authorities;
public LoginUser(User user, List<String> permissions) {
this.user = user;
this.permissions = permissions;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities () {
if (authorities == null)
authorities = permissions.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
return authorities;
}
@Override
public String getPassword () {
return user.getPassword();
}
@Override
public String getUsername () {
return user.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;
}
}
进行配置
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private JwtFilter jwtFilter;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/user/login").anonymous()
.anyRequest().authenticated();
http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
}
}
过滤器
@Component
public class JwtFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String token = request.getHeader("token");
if (StrUtil.isBlank(token)) {
filterChain.doFilter(request, response);
return;
}
User user = new User();
user.setUsername("admin");
user.setPassword("$2a$10$iLLMvl6E9t7qDYexmu65VOM.tVgGwp5wHh5hSG4aC7rYuRoA6I//m");
List<String> list = new ArrayList<>();
list.add("user");
LoginUser loginUser = new LoginUser(user, list);
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
filterChain.doFilter(request, response);
}
}
在LoginService实现类中进行认证
@Service
public class LoginService {
@Resource
private AuthenticationManager manager;
public String login(User user) {
UsernamePasswordAuthenticationToken userAuthentication =
new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
Authentication authenticate = manager.authenticate(userAuthentication);
if (!Objects.isNull(authenticate)) {
LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
User u = loginUser.getUser();
String token = JWT
.create()
.setPayload("userLoginId", u.getId())
.setIssuedAt(new Date())
.setExpiresAt(new Date(System.currentTimeMillis() + DateUnit.WEEK.getMillis()))
.setSigner("HMD5", "salt".getBytes(StandardCharsets.UTF_8))
.sign();
return token;
}
throw new RuntimeException("用户名或密码错误");
}
}
测试
携带刚刚生成的token去访问需要权限的接口