Commit 71d94aa2 authored by liqin's avatar liqin 💬

bug fixed

parent 9c951d26
package cn.wisenergy.web.shiro;
import org.apache.shiro.authc.AuthenticationToken;
/**
......
package cn.wisenergy.web.shiro;
import cn.wisenergy.web.shiro.filter.AuthFilter;
import cn.wisenergy.web.shiro.filter.AuthRealm;
import cn.wisenergy.web.shiro.filter.JwtFilter;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
......@@ -10,6 +12,7 @@ import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import javax.servlet.Filter;
import java.util.HashMap;
......@@ -18,6 +21,7 @@ import java.util.Map;
/**
* shiro配置类
*
* @author 86187
*/
@Configuration
......@@ -48,7 +52,7 @@ public class ShiroConfig {
// 自定义的过滤器
Map<String, Filter> filterMap = new HashMap<>();
// map里面key值要为过滤器的名称,value为过滤器对象
filterMap.put("oauth2", new AuthFilter());
filterMap.put("oauth2", new JwtFilter());
// 将自定义的过滤器加入到过滤器集合中
shiroFilterFactoryBean.setFilters(filterMap);
......@@ -85,34 +89,44 @@ public class ShiroConfig {
return new LifecycleBeanPostProcessor();
}
@Bean
public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setUsePrefix(true);
return defaultAdvisorAutoProxyCreator;
@Bean(name = "authRealm")
@DependsOn("lifecycleBeanPostProcessor")
public AuthRealm authRealm() {
return new AuthRealm();
}
/**
* 配置加密匹配,使用MD5的方式,进行1024次加密
* securityManager 不用直接注入shiroDBRealm,可能会导致事务失效
* 解决方法见 handleContextRefresh
* http://www.debugrun.com/a/NKS9EJQ.html
*/
// @Bean
// public HashedCredentialsMatcher hashedCredentialsMatcher() {
// HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
// hashedCredentialsMatcher.setHashAlgorithmName("MD5");
// hashedCredentialsMatcher.setHashIterations(1024);
// return hashedCredentialsMatcher;
// }
@Bean("securityManager")
public SecurityManager securityManager(AuthRealm authRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(authRealm);
securityManager.setRememberMeManager(null);
/*
* 关闭shiro自带的session,详情见文档
* http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
*/
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
securityManager.setSubjectDAO(subjectDAO);
return securityManager;
}
/**
* 开启Shiro的注解
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public static DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setUsePrefix(true);
// 强制使用cglib,防止重复代理和可能引起代理出错的问题
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
......
package cn.wisenergy.web.shiro.filter;
import cn.wisenergy.common.enums.RespCodeEnum;
import cn.wisenergy.common.utils.HttpContextUtils;
import cn.wisenergy.common.utils.exception.Result;
import cn.wisenergy.web.shiro.AuthToken;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 执行流程preHandle->isAccessAllowed->isLoginAttempt->executeLogin->onLoginSuccess
*/
public class JwtFilter extends BasicHttpAuthenticationFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(JwtFilter.class);
/**
* 最先执行的方法
*/
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
return super.preHandle(request, response);
}
/**
* 这里重写了父类的方法,使用我们自己定义的Token类,提交给shiro。
* 这个方法返回null的话会直接抛出异常,进入isAccessAllowed() 的异常处理逻辑。
*/
@Override
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
//获取请求token
String token = ((HttpServletRequest) request).getHeader("Authorization");
if (StringUtils.isBlank(token)) {
return null;
}
return new AuthToken(token);
}
/**
* 这里我们详细说明下为什么最终返回的都是true,即允许访问
* 例如我们提供一个地址 GET /article
* 登入用户和游客看到的内容是不同的
* 如果在这里返回了false,请求会被直接拦截,用户看不到任何东西
* 所以我们在这里返回true,Controller中可以通过 subject.isAuthenticated() 来判断用户是否登入
* 如果有些资源只有登入用户才能访问,我们只需要在方法上面加上 @RequiresAuthentication 注解即可
* 但是这样做有一个缺点,就是不能够对GET,POST等请求进行分别过滤鉴权(因为我们重写了官方的方法),但实际上对应用影响不大
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
if (isLoginAttempt(request, response)) {
//if (!isLoginAttempt(request, response) || !executeLogin(request,response)) {
try {
executeLogin(request, response);
} catch (UnauthorizedException | AuthenticationException e) {
return false;
}
}
return true;
}
/**
* 判断用户是否想要登入。
* 检测header里面是否包含Authorization字段即可
*/
@Override
protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
HttpServletRequest req = (HttpServletRequest) request;
String authorization = req.getHeader("Authorization");
return authorization != null;
}
/**
*
*/
@Override
protected boolean executeLogin(ServletRequest servletRequest, ServletResponse servletResponse) {
HttpServletRequest request = (HttpServletRequest) servletRequest;
String authorization = getRequestToken(request);
if (StringUtils.isNotBlank(authorization)) {
if (authorization.startsWith("Bearer ")) {
authorization = authorization.substring(7);
}
}
AuthToken token = new AuthToken(authorization);
// 提交给realm进行登入,如果错误他会抛出异常并被捕获
getSubject(servletRequest, servletResponse).login(token);
// 如果没有抛出异常则代表登入成功,返回true
return true;
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
if (isLoginRequest(request, response)) {
return true;
} else {
//获取请求token,如果token不存在,直接返回40101
String token = getRequestToken((HttpServletRequest) request);
if (StringUtils.isBlank(token)) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
//这里是个坑,如果不设置的接受的访问源,那么前端都会报跨域错误,因为这里还没到corsConfig里面
httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());
httpResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setCharacterEncoding("UTF-8");
httpResponse.setContentType("application/json;charset=UTF-8");
httpResponse.setStatus(401);
Result result = new Result();
result.setResult(Result.RESULT_FLG.FAIL.getValue());
result.setErrorCode(RespCodeEnum.NO_AUTH_REQUEST.getCode());
result.setErrorMsg(RespCodeEnum.NO_AUTH_REQUEST.getMsg());
String json = JSON.toJSONString(result);
httpResponse.getWriter().print(json);
return false;
}
}
return executeLogin(request, response);
}
/**
* 将非法请求返回401
*/
private void response401(ServletRequest req, ServletResponse resp) {
try {
HttpServletResponse response = (HttpServletResponse) resp;
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=utf-8");
response.setStatus(401);
response.getWriter().write("{\"status\":401,\"message\":\"未登录!\"}");
} catch (IOException e) {
LOGGER.error(e.getMessage());
}
}
/**
* 将非法请求返回401
*/
private void response403(ServletRequest req, ServletResponse resp) {
try {
HttpServletResponse response = (HttpServletResponse) resp;
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=utf-8");
response.setStatus(403);
response.getWriter().write("{\"status\":403,\"message\":Unauthorized!}");
} catch (IOException e) {
LOGGER.error(e.getMessage());
}
}
/**
* 获取请求头中的token
*/
private String getRequestToken(HttpServletRequest httpRequest) {
//从header中获取token
return httpRequest.getHeader("Authorization");
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment