我们开始resource部分的配置:
先做一下准备工作:
我们新建一个common的module,用于存放公用的代码,比如上次使用的两个工具类以及实体对象类:
pom文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>HandSomeAq_SSO</artifactId>
<groupId>com.hd</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
</dependencies>
</project>
将需要的文件拷贝过来:
最后在auth中添加common的依赖:
<dependency>
<groupId>com.hd</groupId>
<artifactId>common</artifactId>
<version>1.0.0</version>
</dependency>
运行auth查看是否正常。
完成后进行下面的步骤:配置resource部分
我们需要让登录后获得token的用户才可以访问资源,所以我们需要一个拦截器来判断请求是否携带token。
首先修改JwtUtil工具类,增加两个方法,用于解析token及判断token是否有效。
// 解析token
public static Claims getClaimsFromToken(String token){
return Jwts.parser()
.setSigningKey(salt)
.parseClaimsJws(token)
.getBody();
}
//判断token是否有效
public static boolean isTokenExpired(String token){
Claims claims = getClaimsFromToken(token);
Date expiration = claims.getExpiration();
return expiration.before(new Date());
}
接着我们配置拦截器,首先在pom里添加web依赖和common依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.hd</groupId>
<artifactId>common</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
创建TokenInterceptor并继承HandlerInterceptor,
稍微解释一下,HandlerInterceptor用三个抽象类
preHandler:在Controller执行之前调用
postHandler:controller执行之后,且页面渲染之前调用
afterCompletion:页面渲染之后调用,一般用于资源清理操作
所以我们要使用的就是preHandler方法。
package Interceptor;
import com.hd.utils.JwtUtil;
import com.hd.utils.WebUtils;
import io.jsonwebtoken.Claims;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
public class TokenInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception
{
String token = request.getHeader("token");
if ("".equals(token) || token == null){
throw new RuntimeException("please login");
}
if (JwtUtil.isTokenExpired(token)){
throw new RuntimeException("time run out,please login again");
}
Claims claims = JwtUtil.getClaimsFromToken(token);
List<String> list = (List<String>) claims.get("authorities");
String[] strings = list.toArray(new String[list.size()]);
UserDetails userDetails = User.builder()
.username((String) claims.get("username"))
.password("")
.authorities(strings)
.build();
// 构建Security权限交互对象
PreAuthenticatedAuthenticationToken authenticationToken =
new PreAuthenticatedAuthenticationToken(
userDetails,
userDetails.getPassword(),
userDetails.getAuthorities()
);
authenticationToken.setDetails(new WebAuthenticationDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
return true;
}
}
接下来创建拦截器配置文件配置拦截器的作用范围:
package Config;
import Interceptor.TokenInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TokenInterceptor())
//对所有的目录进行拦截
.addPathPatterns("/**");
配置一下SE的配置文件:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(jsr250Enabled = true, prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable();
http
.authorizeRequests()
.anyRequest()
//因为由拦截器来做验证,所以把访问全部打开
.permitAll();
}
}
自己通过SSM的方式写几个接口进行测试:
@RestController
@RequestMapping("/logs")
public class LogsController {
@Autowired
private LogsService logsService;
@GetMapping("/getLogs")
//访问控制:角色限定
@PreAuthorize("hasRole('超级管理员')")
public List<Logs> findLogsByUsername(String Username){
return logsService.findLogsByUsername(Username);
}
@GetMapping("/delete")
//访问控制:权限限定 (CRUD)
@PreAuthorize("hasAuthority('sys:res:delete')")
public String doDelete(){
return "delete success!";
}
}
@PreAuthorize(“hasRole(‘超级管理员’)”)意味着只有超级管理员可以访问;
@PreAuthorize(“hasAuthority(‘sys:res:delete’)”)意味着只有拥有删除权限的角色可以访问.
最后通过postman进行测试:
登录的角色是管理员但没有删除的权限,测试通过.