设为首页 收藏本站
查看: 1280|回复: 0

[经验分享] Springboot集成权限管理框架apache shiro

[复制链接]

尚未签到

发表于 2017-12-24 06:34:41 | 显示全部楼层 |阅读模式
  一、名词解释
  网上一大堆
  二、pom依赖
  

<dependency>  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-spring</artifactId>
  <version>1.2.2</version>
  </dependency>
  <dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-ehcache</artifactId>
  <version>1.2.2</version>
  </dependency>
  

  encache可选,主要用于鉴权时的缓存
  三、shiroConfiguration
  shiro的配置主要是shiroFilter和securityManager的设置
  

@Component  

public>
  @Bean
public EhCacheManager ehCacheManager()  {
  EhCacheManager manager
= new EhCacheManager();  manager.setCacheManagerConfigFile(
"classpath:ehcache-shiro.xml");return manager;  }
  

  @Resource
private MyShiroRealm myShiroRealm;  @Bean
public SecurityManager securityManager()  {
  DefaultWebSecurityManager defaultWebSecurityManager
= new DefaultWebSecurityManager();  defaultWebSecurityManager.setRealm(myShiroRealm);
  defaultWebSecurityManager.setCacheManager(ehCacheManager());
return defaultWebSecurityManager;  }
  @Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager)  {
  ShiroFilterFactoryBean shiroFilterFactoryBean
= new ShiroFilterFactoryBean();  shiroFilterFactoryBean.setSecurityManager(securityManager);
  Map
<String,String> map = new LinkedHashMap<>();  Map
<String,Filter> filterMap = new LinkedHashMap<>();  filterMap.put(
"authc",loginFilter());  filterMap.put(
"perms",myFilter());  shiroFilterFactoryBean.setFilters(filterMap);
  

//map.put("/RPCAFA2A208FA648EA27C1EC30CADFC8B3D","anon");//map.put("/**","authc");  map.put("/RPC52CA3404FDADAB18F91E8210DFCE1522","perms[admin:test]");
  map.put("/RPC66EED9EBACF5FB42B9AD9C069495587F","perms[test]");
  map.put("/**","authc");
  //map.put("/**","myfilter");
  
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
  return shiroFilterFactoryBean;
  }
  @Bean
  public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager)
  {
  AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
  authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
  return authorizationAttributeSourceAdvisor;
  }
  /*@Bean
  public MyShiroRealm myShiroRealm()
  {
  MyShiroRealm myShiroRealm = new MyShiroRealm();
  //myShiroRealm.setCacheManager(manager);
  return myShiroRealm;
  }*/
  @Bean
  public LoginFilter loginFilter()
  {
  return new LoginFilter();
  }
  @Bean
  public MyFilter myFilter()
  {
  return new MyFilter();
  }
  
}
  

  ehCahceManager是注册缓存管理器,MyShiroRealm是权限认证具体的实现,需要注册到securityManager中,shiroFilter中主要设置过滤器链。这里面我主要用到了两个过滤器,perms和authc。
  perms是给访问URL设置访问权限的,比如map.put("/RPC52CA3404FDADAB18F91E8210DFCE1522","perms[admin:test]"),key是访问的URL,value是设置的权限,必须是perms[]的形式。我将需要访问的接口URL放到数据库中,在初始化配置的时候通过读取数据库将每一个需要鉴权的接口进行权限配置。authc要求必须登录认证。
  由于我们是前后端分离,前端通过RPC接口访问后端服务,这块我就想当没有权限或者没有登录时,给前端返回不同的code,所以自己实现了两个filter,loginFilter替换原来的authc过滤器,myFilter替换原来的perms过滤器。
  四、MyFilter和LoginFilter的实现
  loginFilter继承AuthenticationFilter,myFilter继承PermissionsAuthorizationFilter
  

public>@Overrideprotected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o)  {  HttpServletRequest request
= (HttpServletRequest) servletRequest;  Subject subject
= getSubject(servletRequest,servletResponse);  String path
= request.getServletPath();  System.out.println(
"path = " + path);if(path.equals("/RPCAFA2A208FA648EA27C1EC30CADFC8B3D"))  {
return true;  }
if(subject.getPrincipals() != null)  {
return true;  }
return false;  }
/**  * 会话超时或权限校验未通过的,统一返回401,由前端页面弹窗提示
*/  @Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response)throws IOException {  

ShiroUtil.writeResponse((HttpServletResponse) response,new Result(AuthorizationStatus.NOT_LOGIN));  return false;
}  }
  

  首先会执行isAccessAllowed方法,我将登录的几个接口在这里进行排除,直接返回true,就是登录的接口不需要进行登录认证。当返回false时执行onAccessDenied方法,这里我直接通过响应流返回给前端json数据。
  

public>
/**  * 判断是否需要认证
  *
@param bean  *
@return true 不需要  false 需要*/  public static boolean isContains(NotAuthorizationBean bean)
  {
  List<String> paths = bean.getPaths();
  String name = bean.getName();
  for(String path : paths)
  {
  if(path.equalsIgnoreCase(name))
  {
  return true;
  }
  }
  return false;
  }
  

  /**
  * 统一返回前端json数据
  * @param response
  * @param data
  */
  public static void writeResponse(HttpServletResponse response, Object data)
  {
  try {
  response.setContentType("application/json");
  OutputStream outputStream = response.getOutputStream();
  outputStream.write(JSON.toJSONString(data).getBytes("UTF-8"));
  outputStream.flush();
  outputStream.close();
  } catch (IOException e) {
  e.printStackTrace();
  }
  }
  
}
  

  

public enum AuthorizationStatus {  NOT_LOGIN(
401,"没有登录"),  NOT_AUTHORIZATION(
403,"没有授权")  ;
  

private Integer code;  

private String msg;  

  AuthorizationStatus(Integer code, String msg) {
this.code = code;this.msg = msg;  }
  

public Integer getCode() {return code;  }
  

public void setCode(Integer code) {this.code = code;  }
  

public String getMsg() {return msg;  }
  

public void setMsg(String msg) {this.msg = msg;  }
  
}
  

  

public>
private Integer c;  

private String d;  

public Result(AuthorizationStatus status)  {
this.c = status.getCode();this.d = status.getMsg();  }
  

public Result(Integer c, String d) {this.c = c;this.d = d;  }
  

public Integer getC() {return c;  }
  

public void setC(Integer c) {this.c = c;  }
  

public String getD() {return d;  }
  

public void setD(String d) {this.d = d;  }
  
}
  

  myFilter的实现类似,也是重写isAccessAllowed和onAccessDenied两个方法
  

public>@Overridepublic boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws IOException {  HttpServletRequest request
= (HttpServletRequest) servletRequest;  

  String path
= request.getServletPath();  System.out.println(
"request path = " + path);  Subject subject
= getSubject(servletRequest,servletResponse);if(path.equals("/RPCAFA2A208FA648EA27C1EC30CADFC8B3D"))  {
return true;  }
/* String[] perms = (String[])((String[])o);  boolean isPermitted = true;
  if(perms != null && perms.length > 0) {
  if(perms.length == 1) {
  if(!subject.isPermitted(perms[0])) {
  isPermitted = false;
  }
  } else if(!subject.isPermittedAll(perms)) {
  isPermitted = false;
  }
  }
*/  

  return super.isAccessAllowed(servletRequest,servletResponse,o);
  }
  /**
  * 会话超时或权限校验未通过的,统一返回401,由前端页面弹窗提示
  */
  @Override
  protected boolean onAccessDenied(ServletRequest request, ServletResponse response)
  throws IOException {
  System.out.println("no permission");
  Subject subject = getSubject(request,response);
  if(subject.getPrincipal() == null)
  {
  ShiroUtil.writeResponse((HttpServletResponse) response,new Result(AuthorizationStatus.NOT_LOGIN));
  }else{
  ShiroUtil.writeResponse((HttpServletResponse) response,new Result(AuthorizationStatus.NOT_AUTHORIZATION));
  }
  return false;
  }
  
}
  

  五、MyShiroRealm实现
  realm是权限和登录管理的具体实现,需要继承AuthorizingRealm,实现doGetAuthorizationInfo权限认证和doGetAuthenticationInfo登录认证。
  

@Service  

public>@Resourceprivate UserInfoService userInfoService;  @Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {  System.out.println(
"权限认证doGetAuthorizationInfo()");  String username
= (String) super.getAvailablePrincipal(principalCollection);  System.out.println(
"username = " + username);  SimpleAuthorizationInfo simpleAuthorizationInfo
= new SimpleAuthorizationInfo();//simpleAuthorizationInfo.addRole("admin");  simpleAuthorizationInfo.addStringPermission("admin:test");
  return simpleAuthorizationInfo;
  }
  

  @Override
  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
  System.out.println("登陆认证doGetAuthenticationInfo()");
  UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
  System.out.println("token = " + token.getUsername());
  UserInfo userInfo = userInfoService.findByUsername(token.getUsername());
  if(userInfo != null)
  {
  return new SimpleAuthenticationInfo(userInfo.getUsername(),userInfo.getPassword(),getName());
  }
  return null;
  }
  
}
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-427392-1-1.html 上篇帖子: apache+tomcat实现session共享 下篇帖子: 使用Apache Commons Email 发生邮件
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表