密码加密与微服务鉴权JWT-微服务鉴权
微服务鉴权
JWT工具类编写
1)tensquare_common工程引入依赖(考虑到工具类的通用性)
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.6.0</version>
</dependency>
2)修改tensquare_common工程,创建util.JwtUtil
package util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.Date;
/**
* Created by Administrator on 2018/4/11.
*/
@ConfigurationProperties("jwt.config")
public class JwtUtil {
private String key ;
private long ttl ;//一个小时
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public long getTtl() {
return ttl;
}
public void setTtl(long ttl) {
this.ttl = ttl;
}
/**
* 生成JWT
*
* @param id
* @param subject
* @return
*/
public String createJWT(String id, String subject, String roles) {
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
JwtBuilder builder = Jwts.builder().setId(id)
.setSubject(subject)
.setIssuedAt(now)
.signWith(SignatureAlgorithm.HS256, key).claim("roles", roles);
if (ttl > 0) {
builder.setExpiration( new Date( nowMillis + ttl));
}
return builder.compact();
}
/**
* 解析JWT
* @param jwtStr
* @return
*/
public Claims parseJWT(String jwtStr){
return Jwts.parser()
.setSigningKey(key)
.parseClaimsJws(jwtStr)
.getBody();
}
}
3)修改tensquare_user工程的application.yml, 添加配置
jwt:
config:
key: youcan
ttl: 86400000
管理员登陆后台签发token
1)配置bean .修改tensquare_user工程Application类
@Bean
public JwtUtil jwtUtil(){
return new JwtUtil();
}
2)修改AdminController的login方法
@RequestMapping(value = "/login", method = RequestMethod.POST)
public Result login(@RequestBody Admin admin){
Admin adminLogin = adminService.login(admin);
if(adminLogin==null){
return new Result(false, StatusCode.LOGINERROR, "登录失败");
}
//使得前后端可以通话的操作。采用JWT来实现。
//生成令牌
String token = jwtUtil.createJWT(adminLogin.getId(), adminLogin.getLoginname(), "admin");
Map<String, Object> map = new HashMap<>();
map.put("token", token);
map.put("role", "admin");
return new Result(true, StatusCode.OK, "登录成功", map);
}
测试运行结果
{
"flag": true,
"code": 20000,
"message": "登陆成功",
"data": {
"token":
"eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI5ODQzMjc1MDc4ODI5MzgzNjgiLCJzdWIiOiJ4aWF
vbWkiLCJpYXQiOjE1MjM1MjQxNTksInJvbGVzIjoiYWRtaW4iLCJleHAiOjE1MjM1MjQ1MTl9
._YF3oftRNTbq9WCD8Jg1tqcez3cSWoQiDIxMuPmp73o",
"name":"admin"
}
}
删除用户功能鉴权
需求:删除用户,必须拥有管理员权限,否则不能删除。
前后端约定:前端请求微服务时需要添加头信息Authorization ,内容为Bearer+空格+token;
1)修改UserController的delete方法 ,判断请求中的头信息,提取token并验证权限。
@RequestMapping(value="/{id}",method= RequestMethod.DELETE)
public Result delete(@PathVariable String id ){
String authHeader = request.getHeader("Authorization");//获取头信息
if(authHeader==null){
return new Result(false,StatusCode.ACCESSERROR,"权限不足");
}
if(!authHeader.startsWith("Bearer ")){
return new Result(false,StatusCode.ACCESSERROR,"权限不足");
}
String token = authHeader.substring(7);//提取token
Claims claims = jwtUtil.parseJWT(token);
if(claims==null){
return new Result(false,StatusCode.ACCESSERROR,"权限不足");
}
if(!"admin".equals(claims.get("roles"))){
return new Result(false,StatusCode.ACCESSERROR,"权限不足");
}
userService.deleteById(id);
return new Result(true,StatusCode.OK,"删除成功");
}
使用拦截器方式实现token鉴权
如果我们每个方法都去写一段代码,冗余度太高,不利于维护,那如何做使我们的代码看起来更清爽呢?我们可以将这段代码放入拦截器去实现
添加拦截器
Spring为我们提供了org.springframework.web.servlet.handler.HandlerInterceptorAdapter这个适配器,承此类,可以非常方便的实现自己的拦截器。
他有三个方法分别实现:
1)预处理;
2)后处理(调用了Service并返回ModelAndView,但未进行页面渲染);
3)返回处理(已经渲染了页面);
在preHandle中,可以进行编码、安全控制等处理;
在postHandle中,有机会修改ModelAndView;
在afterCompletion中,可以根据ex是否为null判断是否发生了异常,进行日志记录。
1)创建拦截器类。
创建 com.tensquare.user.interceptor.JwtInterceptor ;
package com.tensquare.user.interceptor;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import util.JwtUtil;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class JwtInterceptor implements HandlerInterceptor{
@Autowired
private JwtUtil jwtUtil;
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("经过了拦截器");
return true;
}
}
2)配置拦截器类,创建com.tensquare.user.ApplicationConfig
package com.tensquare.user.config;
import com.tensquare.user.interceptor.JwtInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {
@Autowired
private JwtInterceptor jwtInterceptor;
protected void addInterceptors(InterceptorRegistry registry) {
//注册拦截器要声明拦截器对象和要拦截的请求
registry.addInterceptor(jwtInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/**/login/**");
}
}
拦截器验证token
1)修改拦截器类 JwtFilter
package com.tensquare.user.interceptor;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import util.JwtUtil;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class JwtInterceptor implements HandlerInterceptor{
@Autowired
private JwtUtil jwtUtil;
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("经过了拦截器");
//无论如何都放行。具体能不能操作还是在具体的操作中去判断。
//拦截器只是负责把头请求头中包含token的令牌进行一个解析验证。
String header = request.getHeader("Authorization");
if(header!=null && !"".equals(header)){
//如果有包含有Authorization头信息,就对其进行解析
if(header.startsWith("Bearer ")){
//得到token
String token = header.substring(7);
//对令牌进行验证
try {
Claims claims = jwtUtil.parseJWT(token);
String roles = (String) claims.get("roles");
if(roles!=null && roles.equals("admin")){ // 如果是管理员
request.setAttribute("claims_admin", token);
}
if(roles!=null && roles.equals("user")){ // 如果是用户
request.setAttribute("claims_user", token);
}
}catch (Exception e){
throw new RuntimeException("令牌不正确!");
}
}
}
return true;
}
}
2)修改UserController的delete方法
/**
* 删除 必须有admin角色才能删除
* @param id
*/
@RequestMapping(value="/{id}",method= RequestMethod.DELETE)
public Result delete(@PathVariable String id ){
Claims claims=(Claims) request.getAttribute("admin_claims");
if(claims==null){
return new Result(true,StatusCode.ACCESSERROR,"无权访问");
}
userService.deleteById(id);
return new Result(true,StatusCode.OK,"删除成功");
}