前两天讲解了简单的整合和数据库登录
一:https://blog.csdn.net/weixin_45948218/article/details/118158861?spm=1001.2014.3001.5501
二:https://blog.csdn.net/weixin_45948218/article/details/118161787?spm=1001.2014.3001.5501
今天整合jwt进行token检验,今天在(二)的基础上新增了一些包
直接上代码
UsersController
package com.example.security02.controller;
import com.example.security02.entity.Users;
import com.example.security02.service.UsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/users")
public class UsersController {
@Autowired
UsersService us;
@GetMapping
public Users query(String uname){
return us.query(uname);
}
}
JwtUtils
package com.example.security02.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Map;
public class JwtUtils {
private static final String SECRET ="123456";
/**
* 创建token
* @param user
* @param role
* @return
*/
public static String createToken(String user,String role){
LocalDateTime plus = LocalDateTime.now().plus(60, ChronoUnit.SECONDS);//设置token过期时间,单位秒,可修改
Instant instant = plus.atZone(ZoneId.systemDefault()).toInstant();
Date from = Date.from(instant);
return JWT.create().withSubject(user)
.withClaim("user",user)//用户信息
.withClaim("role",role)//角色信息
.withExpiresAt(from)
.sign(Algorithm.HMAC384(SECRET));//加密方式HMAC384
}
/**
* 校验token
* @param token
* @return
*/
public static Map<String, Claim> check(String token){//校验token
JWTVerifier verifier = JWT.require(Algorithm.HMAC384(SECRET)).build();
return verifier.verify(token).getClaims();
}
}
Results
package com.example.security02.utils;
import java.util.HashMap;
public class Results extends HashMap<String,Object> {
private static final long serialVersionUID = 4718239289210979368L;
public static Results resp(Integer status, String mes, Object data){//可自定义
Results res = new Results();
res.put("status",status);//状态码
res.put("message",mes);//消息
res.put("data",data);//数据
return res;
}
}
SecurityConfig
package com.example.security02.config;
import com.auth0.jwt.interfaces.Claim;
import com.example.security02.utils.JwtUtils;
import com.example.security02.utils.Results;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// super.configure(http);
http.authorizeRequests().antMatchers("/systemUser/add").permitAll();//systemUser/add这个api不需要登录就可以访问,多个用,分隔
//自定义过滤器 在UsernamePasswordAuthenticationFilter之前执行
http.addFilterBefore((req,resp,auth)->{
HttpServletRequest re=(HttpServletRequest)req;//获取request
String token=re.getHeader("token");//获取请求头中的token
try {
if(!ObjectUtils.isEmpty(token)){
//如果不抛出异常,就表示校验通过
Map<String, Claim> check = JwtUtils.check(token);//调用校验方法
String user=check.get("user").asString();
String role=check.get("role").asString();
List<GrantedAuthority> grantedAuthorities = AuthorityUtils.commaSeparatedStringToAuthorityList(role);
//封装auth
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(user, null, grantedAuthorities);
//存入securitycontextholder
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}catch (Exception e){
e.printStackTrace();
Results ok = Results.resp(500, "出错啦!", e.getMessage());
resp.setContentType("application/json;charset=utf-8");
ObjectMapper mapper=new ObjectMapper();
mapper.writeValue(resp.getWriter(),ok);
}
auth.doFilter(req,resp);
}, UsernamePasswordAuthenticationFilter.class);
//关闭默认的session机制
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
//请求没有权限时的异常处理
http.exceptionHandling().authenticationEntryPoint((req,resp,auth)->{
Results ok = Results.resp(403, "请先登录!", "");
resp.setContentType("application/json;charset=utf-8");
ObjectMapper mapper=new ObjectMapper();
mapper.writeValue(resp.getWriter(),ok);
});
http.csrf().disable();
http.formLogin().usernameParameter("user").passwordParameter("pass")
.loginProcessingUrl("/login")
.successHandler((req,resp,auth)->{//成功回调
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
User principal = (User) authentication.getPrincipal();
Collection<GrantedAuthority> authorities = principal.getAuthorities();
String s = StringUtils.collectionToCommaDelimitedString(authorities);
String token = JwtUtils.createToken(principal.getUsername(), s);//调用token创建方法
Results ok = Results.resp(200, "ok", token);//返回token
resp.setContentType("application/json;charset=utf-8");
ObjectMapper mapper=new ObjectMapper();
mapper.writeValue(resp.getWriter(),ok);
})
.failureHandler((req,resp,auth)->{//失败回调
Results ok = Results.resp(500, "error", "");
resp.setContentType("application/json;charset=utf-8");
ObjectMapper mapper=new ObjectMapper();
mapper.writeValue(resp.getWriter(),ok);
})
.permitAll();
http.authorizeRequests().anyRequest().authenticated();
}
}
如果需要跨域代码做如下修改:将最后一行的:
http.authorizeRequests().anyRequest().authenticated();
修改为:
http.authorizeRequests().anyRequest().authenticated().and().cors().and().headers().frameOptions().disable();
并创建CorsConfigurationSource对象放入容器,直接加在SecurityConfig里即可
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("*"));
configuration.addAllowedHeader("*");
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
完成!打开postman测试一下
token过期也会返回相应信息,以此来做前端的判断.
整合jwt到这就完成啦~