springboot 配置 shiro
阿新 • • 發佈:2018-11-09
目錄
前提:
先準備一個 springboot+mybatis 的環境:https://blog.csdn.net/weidong_y/article/details/81709391
一、引入 shiro 的包
<!-- shiro 配置 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency>
二、自定義 realm
MyShiroRealm.java
package com.yyzheng.oa.shiro; import com.yyzheng.oa.dao.User; import com.yyzheng.oa.service.PermissionService; import com.yyzheng.oa.service.RoleService; import com.yyzheng.oa.service.UserService; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.crypto.hash.Md5Hash; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.ByteSource; import org.springframework.beans.factory.annotation.Autowired; import java.util.HashSet; import java.util.List; import java.util.Set; public class MyShiroRealm extends AuthorizingRealm { @Autowired private RoleService roleService; @Autowired private PermissionService permissionService; @Autowired private UserService userService; // 角色許可權和對應許可權新增 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { // 獲取登入使用者名稱 String userName = (String)principalCollection.getPrimaryPrincipal(); // 查詢使用者的角色資訊 Set<String> roles = getRolesByUsername(userName); // 查詢角色的許可權資訊 Set<String> permissions = getPermissionsByUserName(userName); // 設定使用者的角色和許可權 SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); simpleAuthorizationInfo.setRoles(roles); simpleAuthorizationInfo.setStringPermissions(permissions); return simpleAuthorizationInfo; } // 根據使用者名稱字從資料庫中獲取當前使用者的許可權資料 private Set<String> getPermissionsByUserName(String userName) { List<String> list = permissionService.queryPermissionNameByUserName(userName); if( list != null ){ Set<String> sets = new HashSet<>(list); return sets; }else{ return null; } } // 根據使用者名稱字從資料庫中獲取當前使用者的角色資料 private Set<String> getRolesByUsername(String userName) { List<String> list = roleService.queryRoleNameByUsername(userName); if( list != null ){ Set<String> sets = new HashSet<>(list); return sets; }else{ return null; } } // 認證 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { // 1.從主體傳過來的資訊中獲取使用者名稱 String userName = (String)authenticationToken.getPrincipal(); // 2.通過使用者名稱到資料庫獲取憑證 String password = getPasswordByUserName(userName); if( password == null ){ return null; } SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userName,password,"myShiroRealm"); return simpleAuthenticationInfo; } // 通過使用者名稱從資料庫中獲取當前使用者的密碼 private String getPasswordByUserName(String userName) { User user = userService.queryUserByUserName(userName); if( user != null ){ return user.getPassword(); }else{ return null; } } }
三、shiro 配置
package com.yyzheng.oa.config; import com.yyzheng.oa.exception.MyExceptionResolver; import com.yyzheng.oa.shiro.MyShiroRealm; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.HandlerExceptionResolver; import java.util.HashMap; import java.util.Map; @Configuration public class ShiroConfiguration { // 建立自定義 realm @Bean public MyShiroRealm myShiroRealm() { MyShiroRealm myShiroRealm = new MyShiroRealm(); return myShiroRealm; } // 建立 SecurityManager 物件 @Bean public DefaultWebSecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myShiroRealm()); return securityManager; } // Filter工廠,設定對應的過濾條件和跳轉條件 @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); Map<String, String> map = new HashMap<>(); // 登出 map.put("/logout", "logout"); // 對所有使用者認證 map.put("/**", "authc"); // 對登入跳轉介面進行釋放 map.put("/subLogin", "anon"); map.put("/err", "anon"); // 登入 // 注意:這裡配置的 /login 是指到 @RequestMapping(value="/login")中的 /login shiroFilterFactoryBean.setLoginUrl("/login"); // 首頁 shiroFilterFactoryBean.setSuccessUrl("/index"); // 錯誤頁面,認證不通過跳轉 shiroFilterFactoryBean.setUnauthorizedUrl("/err"); shiroFilterFactoryBean.setFilterChainDefinitionMap(map); return shiroFilterFactoryBean; } // 加入註解的使用,不加這個,註解不生效 @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } // 跟上面的註解配置搭配使用,有時候加了上面的配置後註解不生效,需要加入下面的配置 @Bean @ConditionalOnMissingBean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator app = new DefaultAdvisorAutoProxyCreator(); app.setProxyTargetClass(true); return app; } }
四、寫一個 controller 測試
@Controller
public class UserController {
@RequestMapping(value = "/login")
public String login(){
return "/login";
}
@RequestMapping(value = "/err")
public String err(){
return "/err";
}
@RequestMapping(value = "/subLogin")
public String subLogin(User user){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(),user.getPassword());
try{
subject.login(token);
}catch (AuthenticationException e){
e.printStackTrace();
return e.getMessage();
}
return "success";
}
@RequiresRoles(value = "admin")
@RequestMapping(value = "/test")
@ResponseBody
public String test(){
return "123";
}
}
五、無許可權的時候直接報錯的錯誤方式
自定義一個異常攔截,自定義跳轉頁面。
MyExceptionResolver.java 攔截下異常。
package com.yyzheng.oa.exception;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
public class MyExceptionResolver implements HandlerExceptionResolver{
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
System.out.println("==============異常開始=============");
//如果是shiro無權操作,因為shiro 在操作auno等一部分不進行轉發至無許可權url
if(ex instanceof UnauthorizedException){
// 跳轉到 templates 檔案下面找 err.html 頁面
ModelAndView mv = new ModelAndView("err");
return mv;
}
ex.printStackTrace();
ModelAndView mv = new ModelAndView("err");
mv.addObject("exception", ex.toString().replaceAll("\n", "<br/>"));
return mv;
}
}
在shiro中配置一下:
// 自定義異常捕獲註冊
@Bean
public HandlerExceptionResolver solver(){
HandlerExceptionResolver handlerExceptionResolver = new MyExceptionResolver();
return handlerExceptionResolver;
}