springboot整合shiro實現登錄認證以及授權


1.添加shiro的依賴

<dependency>
    <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-web-        
         starter</artifactId>
    <version>1.4.0</version>
</dependency>    

2.先創建一個Realm

public class MyShiroRealm extends AuthorizingRealm {
    @Autowired
    private RoleService roleService;//角色模模塊
    @Autowired
    private UserService userService;//用戶模塊
    @Autowired
    private PermissionService permissionService;//權限模塊
    /**
     * 用戶身份識別(登錄")
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken authToken = (UsernamePasswordToken) authenticationToken;
        // 獲取用戶輸入的賬號
        String userName = authToken.getUsername();
     //通過賬號查找用戶信息 User user
= userService.selectUserOne(userName);// 將賬戶名,密碼,鹽值,getName()實例化到SimpleAuthenticationInfo中交給Shiro來管理 SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo( user, user.getPassWord(),
                                    //這里是設置的密碼鹽 ByteSource.Util.bytes(user.getSalt()), getName());
return authenticationInfo; } /** * 訪問控制。比如某個用戶是否具有某個操作的使用權限 * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); String userName = (String) principalCollection.getPrimaryPrincipal(); if (userName == null) { log.error("授權失敗,用戶信息為空!!!"); return null; } try { //獲取用戶角色集 Set<String> listRole= roleService.findRoleByUsername(userName); simpleAuthorizationInfo.addRoles(listRole); //通過角色獲取權限集 for (String role : listRole) { Set<String> permission= permissionService.findPermissionByRole(role); simpleAuthorizationInfo.addStringPermissions(permission); } return simpleAuthorizationInfo; } catch (Exception e) { log.error("授權失敗,請檢查系統內部錯誤!!!", e); } return simpleAuthorizationInfo; } }

3.創建shiro的配置類

@Configuration
public class ShiroConfiguration {
   //配置自定義的Realm
    @Bean
    public MyShiroRealm myShiroRealm(HashedCredentialsMatcher matcher){
        MyShiroRealm myShiroRealm= new MyShiroRealm();
     //在這里配置密碼加密
        myShiroRealm.setCredentialsMatcher(matcher);
        return myShiroRealm;
    }
  
//將Realm注冊到securityManager中 @Bean public DefaultWebSecurityManager securityManager(HashedCredentialsMatcher matcher){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myShiroRealm(matcher)); return securityManager; } //如果沒有此name,將會找不到shiroFilter的Bean @Bean(name = "shiroFilter") public ShiroFilterFactoryBean shiroFilter(org.apache.shiro.mgt.SecurityManager securityManager){ ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setLoginUrl("/login"); //表示指定登錄頁面 shiroFilterFactoryBean.setSuccessUrl("/user/list"); // 登錄成功后要跳轉的鏈接 shiroFilterFactoryBean.setUnauthorizedUrl("/403"); //未授權頁面 Map<String,String> filterChainDefinitionMap = new LinkedHashMap<>();//攔截器, 配置不會被攔截的鏈接 順序判斷 filterChainDefinitionMap.put("/login","anon"); //所有匿名用戶均可訪問到Controller層的該方法下 filterChainDefinitionMap.put("/userLogin","anon"); filterChainDefinitionMap.put("/image/**","anon"); filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/fonts/**","anon"); filterChainDefinitionMap.put("/js/**","anon"); filterChainDefinitionMap.put("/logout","logout"); filterChainDefinitionMap.put("/**", "authc"); //authc:所有url都必須認證通過才可以訪問; anon:所有url都都可以匿名訪問 //filterChainDefinitionMap.put("/**", "user"); //user表示配置記住我或認證通過可以訪問的地址 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } /** * SpringShiroFilter首先注冊到spring容器 * 然后被包裝成FilterRegistrationBean * 最后通過FilterRegistrationBean注冊到servlet容器 * @return */ @Bean public FilterRegistrationBean delegatingFilterProxy(){ FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); DelegatingFilterProxy proxy = new DelegatingFilterProxy(); proxy.setTargetFilterLifecycle(true); proxy.setTargetBeanName("shiroFilter"); filterRegistrationBean.setFilter(proxy); return filterRegistrationBean; } //設置cookie @Bean public SimpleCookie rememberMeCookie(){ //這個參數是cookie的名稱,對應前端的checkbox的name=rememberMe SimpleCookie simpleCookie = new SimpleCookie("rememberMe"); //記住我cookie生效時間3個小時(單位秒) simpleCookie.setMaxAge(10800); return simpleCookie; } //cookie管理對象,記住我功能 @Bean public CookieRememberMeManager rememberMeManager(){ CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); return cookieRememberMeManager; } /** * 密碼匹配憑證管理器(密碼加密需要此配置) * @return */ @Bean(name = "hashedCredentialsMatcher") public HashedCredentialsMatcher hashedCredentialsMatcher() { HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); hashedCredentialsMatcher.setHashAlgorithmName("MD5"); hashedCredentialsMatcher.setHashIterations(1024);// 設置加密次數 return hashedCredentialsMatcher; } //如果沒有這兩個配置,可能會授權失敗,所以依賴中還需要配置aop的依賴 @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(HashedCredentialsMatcher matcher) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager(matcher)); return authorizationAttributeSourceAdvisor; } @Bean @ConditionalOnMissingBean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){ DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator(); defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); return defaultAdvisorAutoProxyCreator; } }

4.新建controller並寫個登錄的方法

  /**
     * 登錄頁面 這里對應shiro中配置的shiroFilter的登錄方法
     * @return
     */
    @GetMapping("/login")
    public String login() {
        return "user/login";
    }
    //登錄方法
@PostMapping("/userLogin") public String toLogin( String userName,String passWord,Model model){ UsernamePasswordToken token =new UsernamePasswordToken(userName,passWord); Subject subject = SecurityUtils.getSubject(); try {
//這里直接使用shiro的登錄方法 subject.login(token);
return "redirect:user/list";
//登錄失敗時,會catch到你的異常,異常通過全局處理
     //model的msg需要在頁面獲取才能顯示具體失敗信息    }
catch (UnknownAccountException e) { model.addAttribute("msg","該賬號不存在"); } catch (IncorrectCredentialsException e) { model.addAttribute("msg","密碼錯誤,請重試"); } catch (LockedAccountException e) { model.addAttribute("msg","該賬戶已被鎖定,請聯系管理員"); } catch (Exception e) { model.addAttribute("msg","登錄失敗"); } return "user/login"; }
//添加
@RequestMapping("/insertUser")
@ResponseBody
public int insertUser(User user){
//將uuid設置為密碼鹽值
String salt = UUID.randomUUID().toString().replaceAll("-","");
SimpleHash simpleHash = new SimpleHash("MD5", user.getPassWord(), salt, 1024);
   //添加用戶信息
user.setPassWord(simpleHash.toHex()).setValid(1).setSalt(salt).setCreateTime(new Date()).setDel(0);
return userMapper.insertSelective(user);
}
 

5.創建全局異常處理類

@RestControllerAdvice
public class GlobalExceptionHandle {
    @ExceptionHandler(ShiroException.class)
    public String doHandleShiroException(ShiroException se,Model model) {
        se.printStackTrace();
    //這里從登錄方法抓取到異常之后會統一跳轉到登錄頁面
    if(se instanceof UnknownAccountException){      //該賬號不存在
    return "redirect:user/login";
    }
    if(se instanceof LockedAccountException){ //該賬戶已被鎖定,請聯系管理員
    return "redirect:user/login";
    }
    if(se instanceof IncorrectCredentialsException){//密碼錯誤
    return "redirect:user/login";
    }
    if(se instanceof AuthorizationException){ //沒有相應權限,請聯系管理員
    return "redirect:user/login";
    }else{ //登錄失敗
     return "redirect:user/login";
    }
  }
}

權限需要開啟權限注解才生效

    @GetMapping("/userPageList")  
    @ResponseBody
    @RequiresPermissions("user:view") //這里是用戶對應的權限
    public PageList listPage(HttpServletRequest request){
        PageList pageList = new PageList();
        List<User> list= userService.findAllPage(request);//查詢出的條數
        int totalCount = userService.countAll();//總記錄數
        pageList.setRows(list);
        pageList.setTotal(totalCount);
        return pageList;
    }

shiro用戶角色和權限表

-- Table structure for `sys_permission`
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission` (
  `id` int(64) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) DEFAULT NULL,
  `permission` varchar(32) DEFAULT NULL,
  `url` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_permission
-- ----------------------------
INSERT INTO `sys_permission` VALUES ('1', '用戶管理', 'user:view', 'user/userPageList');
INSERT INTO `sys_permission` VALUES ('2', '用戶添加', 'user:add', 'user/saveUser');
INSERT INTO `sys_permission` VALUES ('3', '用戶刪除', 'user:del', 'user/delById');

-- ----------------------------
-- Table structure for `sys_role`
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
  `id` int(64) NOT NULL,
  `available` varchar(8) DEFAULT NULL,
  `description` varchar(32) DEFAULT NULL,
  `role` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES ('1', '1', '管理員', 'admin');
INSERT INTO `sys_role` VALUES ('2', '1', 'VIP會員', 'vip');

-- ----------------------------
-- Table structure for `sys_role_permission`
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_permission`;
CREATE TABLE `sys_role_permission` (
  `permission_id` int(64) NOT NULL COMMENT '權限表主鍵',
  `role_id` int(64) NOT NULL COMMENT '角色表主鍵'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_role_permission
-- ----------------------------
INSERT INTO `sys_role_permission` VALUES ('1', '1');
INSERT INTO `sys_role_permission` VALUES ('2', '1');

-- ----------------------------
-- Table structure for `sys_user_role`
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
  `role_id` int(64) NOT NULL,
  `user_id` int(64) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES ('1', '1');

-- ----------------------------
-- Table structure for `user_info`
-- ----------------------------
DROP TABLE IF EXISTS `user_info`;
CREATE TABLE `user_info` (
  `id` int(64) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) DEFAULT NULL,
  `password` varchar(64) DEFAULT NULL,
  `salt` varchar(64) DEFAULT NULL,
  `state` varchar(8) DEFAULT NULL,
  `username` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user_info
-- ----------------------------
INSERT INTO `user_info` VALUES ('1', '管理員', 'd3c59d25033dbf980d29554025c23a75', '8d78869f470951332959580424d4bf4f', '1', 'admin');

最后聲明下!!!我的開發環境是windows10+JDK1.8+springboot2.1.7+shiro1.4.0


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM