SpringSecurity整合JWT
1.数据库
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`id` int(0) NOT NULL AUTO_INCREMENT,
`name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`name_zh` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `role` VALUES (1, 'ROLE_product', '商品管理员');
INSERT INTO `role` VALUES (2, 'ROLE_admin', '系统管理员');
INSERT INTO `role` VALUES (3, 'ROLE_user', '用户管理员');
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(0) NOT NULL AUTO_INCREMENT,
`username` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`enabled` tinyint(1) NULL DEFAULT NULL,
`account_non_expired` tinyint(1) NULL DEFAULT NULL,
`account_non_locked` tinyint(1) NULL DEFAULT NULL,
`credentials_non_expired` tinyint(1) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `user` VALUES (1, 'root', '{noop}123', 1, 1, 1, 1);
INSERT INTO `user` VALUES (2, 'admin', '{noop}123', 1, 1, 1, 1);
INSERT INTO `user` VALUES (3, 'common', '{noop}123', 1, 1, 1, 1);
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
`id` int(0) NOT NULL AUTO_INCREMENT,
`uid` int(0) NULL DEFAULT NULL,
`rid` int(0) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `uid`(`uid`) USING BTREE,
INDEX `rid`(`rid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `user_role` VALUES (1, 1, 1);
INSERT INTO `user_role` VALUES (2, 1, 2);
INSERT INTO `user_role` VALUES (3, 2, 2);
INSERT INTO `user_role` VALUES (4, 3, 3);
SET FOREIGN_KEY_CHECKS = 1;
2.导入依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.21</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
3.创建各种类
3.1实体类
实体类应该实现security的用户实体类(UserDetails)
package com.example.securitystu5.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements UserDetails {
private Integer id;
private String username;
private String password;
private Boolean enabled;
private Boolean accountNonExpired;
private Boolean accountNonLocked;
private Boolean credentialsNonExpired;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
@Override
public boolean isAccountNonExpired() {
return accountNonExpired;
}
@Override
public boolean isAccountNonLocked() {
return accountNonLocked;
}
@Override
public boolean isCredentialsNonExpired() {
return credentialsNonExpired;
}
@Override
public boolean isEnabled() {
return enabled;
}
}
3.2dao
@Mapper
public interface UserDAO extends BaseMapper<User> {
}
3.3服务层
用户登陆的 实体类要实现UserDetailsService,security会自动调用loadUserByUsername()方法
@Service
public class MyUserService implements UserDetailsService {
@Autowired
UserDAO userDAO;
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
return userDAO.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, userName));
}
}
3.4配置类
@Configuration
public class ScurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
JwtFilter jwtFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().exceptionHandling().authenticationEntryPoint(new MyAuthenticationEntryPoint())
.and().csrf().disable();
http.addFilterAt(LoginFilter(), UsernamePasswordAuthenticationFilter.class);
http.addFilterBefore(jwtFilter, LoginFilter.class);
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public LoginFilter LoginFilter() throws Exception {
LoginFilter loginFilter = new LoginFilter();
loginFilter.setFilterProcessesUrl("/doLogin");
loginFilter.setUsernameParameter("uname");
loginFilter.setPasswordParameter("passwd");
loginFilter.setAuthenticationManager(authenticationManagerBean());
loginFilter.setAuthenticationSuccessHandler(new MyAuthenticationSuccessHandler());
loginFilter.setAuthenticationFailureHandler(new MyAuthenticationFailureHandler());
return loginFilter;
}
}
3.5成功、失败、未授权响应
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
Map<String, Object> result = new HashMap<String, Object>();
result.put("msg", "登录成功");
result.put("status", 200);
result.put("token", request.getAttribute("token"));
response.setContentType("application/json;charset=UTF-8");
String s = new ObjectMapper().writeValueAsString(result);
response.getWriter().println(s);
}
}
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
Map<String, Object> result = new HashMap<String, Object>();
result.put("msg", "登录失败: "+exception.getMessage());
result.put("status", 500);
response.setContentType("application/json;charset=UTF-8");
String s = new ObjectMapper().writeValueAsString(result);
response.getWriter().println(s);
}
}
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=UTF-8");
httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
httpServletResponse.getWriter().println("必须认证之后才能访问!");
}
}
3.6jwt工具类
@Component
public class JwtUtils {
private static final String SING = "123456";
private static final Long EXPIRES =60000*60L;
public static String creatToken(Map<String,String> map){
JWTCreator.Builder jwt = JWT.create();
map.forEach((k,v)->{
jwt.withClaim(k,v);
});
return jwt.withExpiresAt(new Date(System.currentTimeMillis()+EXPIRES)).sign(Algorithm.HMAC256(SING));
}
public static DecodedJWT verification(String token) {
return JWT.require(Algorithm.HMAC256(SING)).build().verify(token);
}
}
3.7jwt过滤器
@Component
public class JwtFilter extends OncePerRequestFilter {
@Autowired
JwtUtils jwtUtils;
@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) throws IOException, ServletException {
String token = req.getHeader("token");
if (!ObjectUtils.isEmpty(token)){
DecodedJWT verification = jwtUtils.verification(token);
User user = new User();
user.setUsername(verification.getClaim("uname").asString());
user.setPassword(verification.getClaim("passwd").asString());
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(user,null,null);
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
filterChain.doFilter(req,res);
}
filterChain.doFilter(req,res);
}
}
3.8认证过滤器
public class LoginFilter extends UsernamePasswordAuthenticationFilter {
@Autowired
JwtUtils jwtUtils;
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (!request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
Map<String, String> userInfo = null;
try {
userInfo = new ObjectMapper().readValue(request.getInputStream(), Map.class);
String username = userInfo.get(getUsernameParameter());
String password = userInfo.get(getPasswordParameter());
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
HashMap<String, String> map = new HashMap<>();
map.put("uname",username);
map.put("passwd",password);
request.setAttribute("token",jwtUtils.creatToken(map));
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
} catch (IOException e) {
e.printStackTrace();
}
throw new AuthenticationServiceException("失败");
}
}
|