1. 程式人生 > 實用技巧 >Shiro+SpringBoot認證

Shiro+SpringBoot認證

該部落格以Web為基礎

一、引入依賴

    shiro-all包含shiro所有的包、shiro-core是核心包、shiro-web是與web整合、shiro-spring是與spring整合、shiro-ehcache是與EHCache整合、shiro-quartz是與任務排程quartz整合等等。這裡我們只需要引入shiro-spring即可。

1 <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
2 <dependency>
3      <groupId>org.apache.shiro</groupId>
4      <artifactId>shiro-spring</artifactId>
5      <version>1.5.3</version>
6 </dependency>

二、Controller層

@RestController
@RequestMapping("/account")
public class AccountController {

/**
* 登入
* @param username
 * @param password
* @return
*/

  @PostMapping(path = "/login")
public ResultMsg login(
@RequestParam(value = "aaccount")String username,
@RequestParam(value = "apassword")String pwd,
@RequestParam("check") Integer check ) {
ResultMsg resultMsg = new ResultMsg();
// 獲取當前使用者
Subject subject = SecurityUtils.getSubject();
/**
* 判斷當前使用者是否已經認證過
*/
// System.out.println("是否記住我==="+subject.isRemembered());
if (!subject.isAuthenticated()) {
// 封裝使用者的登入資料
UsernamePasswordToken token = new UsernamePasswordToken(username,pwd);
Boolean rememberMe = check == 1 ? true:false;
System.out.println(rememberMe);
token.setRememberMe(rememberMe); //記住我
try {
subject.login(token); //登入認證
resultMsg.setState(200);
resultMsg.setMsg("登入成功");
return resultMsg;
} catch (UnknownAccountException u) {
System.err.println("使用者不存在");
resultMsg.setState(412);
resultMsg.setMsg("使用者不存在");
return resultMsg;
} catch (IncorrectCredentialsException i) {
System.err.println("密碼錯誤");
resultMsg.setState(412);
resultMsg.setMsg("密碼錯誤");
return resultMsg;
} catch (LockedAccountException l) {
System.err.println("賬戶鎖定");
resultMsg.setState(412);
resultMsg.setMsg("賬戶鎖定");
return resultMsg;
}
} else {
resultMsg.setState(403);
resultMsg.setMsg("此賬戶已在其他地方登入,是否強制下線?");
return resultMsg;
}
}
  
  /**
* 退出登入
* @param num
* @return
*/
@GetMapping(path = "/loginout")
public ResultMsg loginOut(Integer num) {
ResultMsg resultMsg = new ResultMsg();
// 獲取當前使用者
Subject subject = SecurityUtils.getSubject();
subject.logout();//退出當前登入
resultMsg.setState(200);
if (num == 1) {
resultMsg.setMsg("已下線!");
} else {
resultMsg.setMsg("當前使用者已退出!");
}
return resultMsg;

}
  
  /**
  * 未認證返回登入頁面
  * @return
  */
  @GetMapping(path = "/login")
  public ModelAndView login() {
  ModelAndView mv = new ModelAndView("/user/login");
  return mv;
  }


}

Shiro核心配置

Shiro配置類

ShiroConfig.java

主要建立三大Bean物件

  • ShiroFilterFactoryBean(攔截一切請求)3
  • DefaultSecurityManager(安全管理器)2
  • 自定義Realm 繼承 AuthorizingRealm(主要用於認證和授權)1

建議建立順序逆行

package com.hk.aefz.shiro.config;
@Configuration public class ShiroConfig { // ShiroFliterFactoryBean 3 @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean( @Qualifier("securityManager") DefaultWebSecurityManager securityManager ) { ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean(); // 設定安全管理器 factoryBean.setSecurityManager(securityManager); // 新增Shiro內建過濾器
    /*
anon:無需認證就可以訪問
authc:必須認證才可以訪問
user:必須擁有記住我功能才可以訪問
perms:擁有對某個資源的許可權才能訪問
role:擁有某個角色許可權才可以訪問
*/
Map<String, String> filterMap = new LinkedHashMap<>(); // 匿名訪問 filterMap.put("/navigation/index","anon"); filterMap.put("/navigation/blogdetails","anon"); filterMap.put("/navigation/login","anon"); filterMap.put("/navigation/register","anon"); // 需要角色 filterMap.put("/navigation/personblog","authc,roles[blogger]"); filterMap.put("/navigation/admin-blog","authc,roles[blogger]"); filterMap.put("/navigation/**","user"); factoryBean.setFilterChainDefinitionMap(filterMap); // 攔截後返回登入頁面 factoryBean.setLoginUrl("/navigation/login");return factoryBean; } // DefaultWebSecurityManager 2 安全管理器 @Bean(name = "securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager( @Qualifier("userRealm") UserRealm userRealm, ) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 關聯UserRealm securityManager.setRealm(userRealm); return securityManager; } // 建立UserRealm類 需要自定義 1 @Bean public UserRealm userRealm() { UserRealm userRealm = new UserRealm(); return userRealm; } } }

自定義Relam類

繼承AuthorizingRealm類

/**
 * 自定義UserRealm
 */
public class UserRealm extends AuthorizingRealm {

//    注入AccountController
    @Autowired
    private AccountController accountController;

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private AccountService accountService;

//    授權
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.err.println("執行了授權.........");return null;
    }

//    認證
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.err.println("執行了認證...........");
//        獲取當前登入賬戶
        UsernamePasswordToken accountToken = (UsernamePasswordToken) token;
        String username = accountToken.getUsername(); // 獲取當前賬號
//        連線資料庫進行登入驗證
        Account account = accountController.selectByName(username);
        System.out.println(account);
        if (account == null) {
            return null; //丟擲 UnknownAccountException 異常
        }
//         密碼認證 shiro做 存在洩密
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(account, account.getApassword(), account.getAaccount());return info;
    }

}

測試

使用PostMan進行登入測試