I. Introduction to Shiro

1. Basic concepts

Apache Shiro is a powerful and easy-to-use Java security framework that performs authentication, authorization, password, and session management. Shiro is cleverly designed as a security framework. Shiro’s application does not depend on any container, and it can be used not only under JavaEE, but also in a JavaSE environment.

2. Core roles

1) Subject: authentication Subject

The user that represents the current system is the user. In Shiro’s authentication, the authentication subject is usually userName and passWord, or other unique identifiers related to the user.

2) SecurityManager: SecurityManager

The core component of Shiro’s architecture that coordinates user authentication and authorization with other components. In effect, the SecurityManager is the controller of Shiro’s framework.

Realm: Realm objects

Defines how to access data to connect to different data sources, such as relational databases, configuration files, and so on.

3. Core concepts

Shiro does not maintain users and permissions itself, but authenticates and authorizes users through the injection of Subject user principals and Realm objects.

Second, integrate the SpringBoot2 framework

1. Core dependencies

<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> < version > 1.4.0 < / version > < / dependency > < the dependency > < groupId >. Org. Apache shiro < / groupId > < artifactId > shiro - spring < / artifactId > < version > 1.4.0 < / version > < / dependency >Copy the code

Shiro core configuration

Configurationpublic class ShiroConfig {/** * Session Manager: Configurationpublic class ShiroConfig {/** * Session Manager: Configurationpublic class ShiroConfig {/** * * Sessions can be in a normal JavaSE environment or in a Web environment; */ @Bean("sessionManager") public SessionManager sessionManager(){ DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); / / set the session expiration time our sessionManager. SetGlobalSessionTimeout (60 * 60 * 1000); sessionManager.setSessionValidationSchedulerEnabled(true); / / remove shiro login url in the JSESSIONID. Our sessionManager setSessionIdUrlRewritingEnabled (false); return sessionManager; } /** * SecurityManager: SecurityManager public securityManager securityManager(UserRealm UserRealm, SessionManager sessionManager) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setSessionManager(sessionManager); securityManager.setRealm(userRealm); return securityManager; } /** * ShiroFilter is the entry point of Shiro. */ @bean ("shiroFilter") public ShiroFilterFactoryBean shiroFilter(SecurityManager SecurityManager) { ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean(); shiroFilter.setSecurityManager(securityManager); shiroFilter.setLoginUrl("/userLogin"); shiroFilter.setUnauthorizedUrl("/"); Map<String, String> filterMap = new LinkedHashMap<>(); filterMap.put("/userLogin", "anon"); shiroFilter.setFilterChainDefinitionMap(filterMap); return shiroFilter; } / * * * some bean lifecycle management Shiro * / @ bean (" lifecycleBeanPostProcessor ") public lifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } /** * Scan the context for all Advistor * apply these Advisors to all beans that match the pointcut. */ @Bean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator(); proxyCreator.setProxyTargetClass(true); return proxyCreator; Added Shiro} / * * * matches all certification annotated method * / @ Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new  AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; }}Copy the code

3. Domain object configuration

@Componentpublic class UserRealm extends AuthorizingRealm { @Resource private SysUserMapper sysUserMapper ; @Resource private SysMenuMapper sysMenuMapper ; Override public AuthorizationInfo doGetAuthorizationInfo (PrincipalCollection principals) { SysUserEntity user = (SysUserEntity)principals.getPrimaryPrincipal(); If (user == null) {throw new UnknownAccountException(" Account does not exist "); } List<String> permsList; List<SysMenuEntity> menuList = sysmEnumapper.selectList (); // The default user has the highest permission. permsList = new ArrayList<>(menuList.size()); for(SysMenuEntity menu : menuList){ permsList.add(menu.getPerms()); } // Set<String> permsSet = new HashSet<>(); for(String perms : permsList){ if(StringUtils.isEmpty(perms)){ continue; } permsSet.addAll(Arrays.asList(perms.trim().split(","))); } SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.setStringPermissions(permsSet); return info; } /** * Authentication (invoked when logging in) */ @override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken)authToken; SysUserEntity user = sysusermapper.selectOne (tok.getUsername ()); SysUserEntity user = sysusermapper.selectOne (tok.getUsername ()); If (user == null) {throw new UnknownAccountException(" Incorrect "); If (user.getStatus() == 0){throw new LockedAccountException(" Account is locked, please contact the administrator "); } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo (user, user.getPassword(), ByteSource.Util.bytes(user.getSalt()), getName()); return info; } @Override public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) { HashedCredentialsMatcher shaCredentialsMatcher = new HashedCredentialsMatcher(); shaCredentialsMatcher.setHashAlgorithmName(ShiroUtils.hashAlgorithmName); shaCredentialsMatcher.setHashIterations(ShiroUtils.hashIterations); super.setCredentialsMatcher(shaCredentialsMatcher); }}Copy the code

4. Core tool classes

Public class ShiroUtils {/** ENCRYPTION algorithm */ public final Static String hashAlgorithmName = "SHA-256"; /** Iterations */ public final static int hashIterations = 16; public static String sha256(String password, String salt) { return new SimpleHash(hashAlgorithmName, password, salt, hashIterations).toString(); Admin public static void main(String[] args) {// 3743a4c09a17e6f2829febd09ca54e627810001cf255ddcae9dabd288a949c4a System.out.println(sha256("admin","123")) ; } /** * getSession */ public static Session getSession() {return securityutils.getsubject ().getsession (); } public static Subject getSubject() {return securityutils.getSubject ();} public static Subject getSubject() {return securityutils.getSubject (); } public static SysUserEntity getUserEntity() { return (SysUserEntity)SecurityUtils.getSubject().getPrincipal(); } public static Long getUserId() { return getUserEntity().getUserId(); } public static void setSessionAttribute(Object key, Object value) { getSession().setAttribute(key, value); } public static Object getSessionAttribute(Object key) { return getSession().getAttribute(key); } public static boolean isLogin() { return SecurityUtils.getSubject().getPrincipal() ! = null; } public static void logout() { SecurityUtils.getSubject().logout(); }}Copy the code

5. Custom permission exception message is displayed

@RestControllerAdvicepublic class ShiroException { @ExceptionHandler(AuthorizationException.class) public String AuthorizationException (){return "Sorry you don't have permission to access this content!" ; } @ExceptionHandler(exception.class) public String handleException(Exception e){return "System Exception!" ; }}Copy the code

Three, case demonstration code

1. Test interface

@RestControllerpublic class ShiroController { private static Logger LOGGER = LoggerFactory.getLogger(ShiroController.class) ; @Resource private SysMenuMapper sysMenuMapper ; / * * * * http://localhost:7011/userLogin? login test userName=admin&passWord=admin */ @RequestMapping("/userLogin") public void userLogin ( @RequestParam(value = "userName")  String userName, @RequestParam(value = "passWord") String passWord){ try{ Subject subject = ShiroUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(userName, passWord); subject.login(token); Logger. info(" Login successful "); }catch (Exception e) { e.printStackTrace(); }} / * * * server every time to restart the interface must be first request login interface * http://localhost:7011/menu/list for all the above menu list * permission demands: sys:user:shiro */ @RequestMapping("/menu/list") @RequiresPermissions("sys:user:shiro") public List list(){ return sysMenuMapper.selectList() ; } /** * The user does not have the permission to access * ccc:ddd:bbb */ @RequestMapping("/menu/list2") @RequiresPermissions("ccc:ddd:bbb") public List list2(){ return sysMenuMapper.selectList() ; */ @requestMapping ("/userLogOut") public String logout() {shiroutils.logout (); return "success" ; }}Copy the code

2. Test process

1), obtain permission to http://localhost:7011/userLogin? after login UserName = admin&passWord = admin2), no access permissions interface http://localhost:7011/menu/list3), access interface http://localhost:7011/menu/list24), log out h ttp://localhost:7011/userLogOutCopy the code

Source code address

Making address: given a smile cloud address: https://github.com/cicadasmile/middle-ware-parent code laughed told https://gitee.com/cicadasmile/middle-ware-parentCopy the code