jwt实现权限认证
pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<!--jwt-->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
<scope>compile</scope>
</dependency>
<!--json-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68</version>
</dependency>
禁用session生成
/**
* @author spp
* @date 2020-06-13 17:35
**/
public class StatelessDefaultSubjectFactory extends DefaultWebSubjectFactory {
@Override
public Subject createSubject(SubjectContext context) {
//禁用生成session
context.setSessionCreationEnabled(false);
return super.createSubject(context);
}
}
shiro配置类
/**
* @author spp
* @date 2020-06-13 17:13
**/
@Configuration
public class ShiroConfig {
//ShiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean getFactory(@Autowired DefaultWebSecurityManager manager){
ShiroFilterFactoryBean factory = new ShiroFilterFactoryBean();
//设置安全管理器
//添加shiro的内置过滤器
/*
anon:无需认证就可以访问
authc:必须认证了才能访问
user: 必须 设置 记住我才能访问
perms: 拥有对某个资源的权限才能登陆
role: 拥有某个角色权限才能访问
*/
factory.setSecurityManager(manager);
factory.getFilters().put("jwt",new JwtFilter());
Map<String,String> filterMap = new LinkedHashMap<>();
//filterMap.put("/login","anon");
filterMap.put("/**","jwt");
factory.setFilterChainDefinitionMap(filterMap);
factory.setLoginUrl("/login");
factory.setUnauthorizedUrl("/unauthorized");
return factory;
}
@Bean
@Autowired
public DefaultWebSecurityManager getManager(MyRealm realm){
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
DefaultSessionManager defaultSessionManager = new DefaultSessionManager ();
defaultSessionManager.setSessionValidationSchedulerEnabled(false);
//禁用session
manager.setSubjectFactory(new StatelessDefaultSubjectFactory());
manager.setSessionManager(defaultSessionManager);
// 禁用Session作为存储策略的实现。
DefaultSubjectDAO defaultSubjectDAO = (DefaultSubjectDAO) manager.getSubjectDAO();
DefaultSessionStorageEvaluator defaultSessionStorageEvaluatord = (DefaultSessionStorageEvaluator) defaultSubjectDAO
.getSessionStorageEvaluator();
defaultSessionStorageEvaluatord.setSessionStorageEnabled(false);
manager.setRealm(realm);
return manager;
}
}
自定义的jwt过滤器,继承BasicHttpAuthenticationFilter
/**
* @author spp
* @date 2020-06-13 17:31
**/
@Slf4j
public class JwtFilter extends BasicHttpAuthenticationFilter {
private static final String LOGIN = "/login";
private static final String SECRET_KEY = "auth_sp";
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
log.info("isAccessAllowed");
HttpServletRequest r = (HttpServletRequest) request;
if (LOGIN.equals(r.getRequestURI())){
return true;
}
String token = r.getHeader(SECRET_KEY);
try {
Boolean expired = JwtTokenUtil.isTokenExpired(token);
if (!expired){
User u = JwtTokenUtil.getUsernameFromToken(token);
log.info(u.toString() + "--->进行jwt认证");
return true;
}
return false;
} catch (Exception e) {
request.setAttribute("error",e.getMessage());
return false;
}
}
//认证失败
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
response.setContentType("application/json;charset=utf8");
Object error = request.getAttribute("error");
if(!ObjectUtils.isEmpty(error)){
response.getWriter().println(error);
return false;
}
response.getWriter().println("error");
return false;
}
}
jwt工具类
/**
* JWT生成令牌、验证令牌、获取令牌
* @author 76986
*/
@Component
@NoArgsConstructor
public class JwtTokenUtil {
/**
* 私钥
*/
private static final String SECRET_KEY = "auth_sp";
/**
* 过期时间 毫秒,设置默认两小时过期
*/
private static final long EXPIRATION_TIME = 3600000L * 2;
/**
* 生成令牌
* @param user 用户
* @return 令牌
*/
public static String generateToken(User user) {
Map<String, Object> claims = new HashMap<>(2);
claims.put(Claims.SUBJECT,user);
claims.put(Claims.ISSUED_AT, new Date());
return generateToken(claims);
}
/**
* 从令牌中获取用户
* @param token 令牌
* @return 用户名
*/
public static User getUsernameFromToken(String token) {
User user = new User();
try {
Claims claims = getClaimsFromToken(token);
String subject = claims.getSubject();
subject = subject.replace("{","").replace("}","");
String[] split = subject.split(",");
user.setUsername(split[0].split("=")[1]);
user.setPassword(split[1].split("=")[1]);
System.out.println(user);
} catch (Exception e) {
System.out.println("e = " + e.getMessage());
}
return user;
}
/**
* 判断令牌是否过期
*
* @param token 令牌
* @return 是否过期
*/
public static Boolean isTokenExpired(String token) throws Exception{
try {
Claims claims = getClaimsFromToken(token);
Date expiration = claims.getExpiration();
return expiration.before(new Date());
} catch (Exception e) {
throw new Exception("签名过期或者token不正确");
}
}
/**
* 刷新令牌
*
* @param token 原令牌
* @return 新令牌
*/
public static String refreshToken(String token) {
String refreshedToken;
try {
Claims claims = getClaimsFromToken(token);
claims.put(Claims.ISSUED_AT, new Date());
refreshedToken = generateToken(claims);
} catch (Exception e) {
refreshedToken = null;
}
return refreshedToken;
}
/**
* 从数据声明生成令牌
*
* @param claims 数据声明
* @return 令牌
*/
private static String generateToken(Map<String, Object> claims) {
Date expirationDate = new Date(System.currentTimeMillis()+ EXPIRATION_TIME);
HashMap<String, Object> map = new HashMap<>(1);map.put("typ",Header.JWT_TYPE);
return Jwts.builder().setHeader(map).setClaims(claims).setExpiration(expirationDate).signWith(SignatureAlgorithm.HS512, SECRET_KEY).compact();
}
/**
* 从令牌中获取数据声明
*
* @param token 令牌
* @return 数据声明
*/
private static Claims getClaimsFromToken(String token) throws Exception {
Claims claims = null;
try {
claims = Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
} catch (Exception e) {
new Throwable(e);
}
return claims;
}
}
登陆控制器
/**
* @author spp
* @date 2020-06-13 18:23
**/
@RestController
public class Index {
private Logger logger = LoggerFactory.getLogger(Index.class);
@GetMapping("/login")
public R login(User user){
UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(),user.getPassword());
try {
SecurityUtils.getSubject().login(token);
}catch (IncorrectCredentialsException e){
return new R(ApiErrorCode.FAILED).setMsg(e.getMessage());
}
String s = JwtTokenUtil.generateToken(user);
logger.info(s);
return new R(ApiErrorCode.SUCCESS).setMsg("登陆成功");
}
}
自定义登陆处理类
/**
* @author 76986
*/
@Component
public class MyRealm extends AuthorizingRealm {
/**
* 授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
/**
* 登陆
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken tok = (UsernamePasswordToken) authenticationToken;
User user = new User("admin","123456");
return new SimpleAuthenticationInfo(user, user.getPassword(),getName());
}
}
测试
先登陆拿token
携带token访问