Subject 用户主体 (把操作交给SecurityManager)
SecurityManager 安全管理器 (关联Realm)
Realm Shiro连接数据的桥梁
引入maven依赖
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency>
配置自定义Realm
UserRealm.java
package com.shiro; import com.entity.User; import com.service.UserService; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.session.Session; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; import org.springframework.beans.factory.annotation.Autowired; import java.util.ArrayList; import java.util.List; /** * 自定义realm */ public class UserRealm extends AuthorizingRealm { @Autowired private UserService userService; /** * 执行授权逻辑 * * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { //给请求进行授权 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //获取登录用户信息 Subject subject = SecurityUtils.getSubject(); //取出来的user与下方认证方法中new SimpleAuthenticationInfo(user, user.getPassword(), getName());的第一个存入的参数对应 User user = (User) subject.getPrincipal(); //这里为了做演示,实际开发中需要从数据库获取该用户的权限 List permList = new ArrayList(); permList.add("user:delete"); //添加请求的授权集合 info.addStringPermissions(permList); return null; } /** * 执行认证逻辑 * * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; //查询用户名是否存在 User user = userService.findByUserName(token.getUsername()); if (user == null) { //用户不存在,shiro底层会抛出UnknownAccountException异常 throw new UnknownAccountException(); } if (!user.getEnable()) { throw new LockedAccountException(); } //通过这个进行认证,并返回 实际使用中密码要进行加密 这里放入的第一个参数user和上面授权方法中subject.getPrincipal();这个取到的内容对应 SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), getName()); // 当验证都通过后,把用户信息放在session里 Session session = SecurityUtils.getSubject().getSession(); session.setAttribute("user", user); return simpleAuthenticationInfo; } }
shiro配置类
ShiroConfig.java
package com.shiro; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.LinkedHashMap; import java.util.Map; /** * shiro配置类 */ @Configuration public class ShiroConfig { /** * 创建shiroFilterFatoryBean */ @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(){ ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean(); //设置安全管理器 shiroFilterFactoryBean.setSecurityManager(getDefaultWebSecurityManager()); //添加shiro内置过滤器 /** * shiro内置过滤器,可以实现权限相关的拦截器功能 * 常用的过滤器 * anon:无需认证(登录)可以访问 * authc:必须认证才可以访问 * user:如果使用rememberMe的功能可以直接访问 * perms:该资源必须得到资源权限才可以访问 * role:该资源必须得到角色权限才可以访问 * */ Map<String,String> filterMap=new LinkedHashMap<>(); filterMap.put("/back/*","authc"); //放行登录页面和登录提交请求 filterMap.put("/login","anon"); filterMap.put("/toLogin","anon"); /** * 授权过滤器,表示用户执行 “/delete” 操作需要有 “user:delete” 的授权 * 当前授权拦截后,shiro会自动跳转到未授权页面 */ filterMap.put("/delete","perms[user:delete]"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); //设置登录页面的请求链接 shiroFilterFactoryBean.setLoginUrl("/toLogin"); //设置未授权时的跳转链接 shiroFilterFactoryBean.setUnauthorizedUrl("/toUnauthorizedUrl"); return shiroFilterFactoryBean; } /** * 创建DefaultWebSecurityManager */ @Bean public DefaultWebSecurityManager getDefaultWebSecurityManager(){ DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager(); //关联realm securityManager.setRealm(getRealm()); return securityManager; } /** * 创建Realm */ @Bean public UserRealm getRealm(){ return new UserRealm(); } }
配置规则详细说明
// 将需要配置的地址放入map中,规则如下: /** anon:例子/admins/**=anon 没有参数,表示可以匿名使用。 authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,没有参数 roles(角色):例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号, 并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles["admin,guest"], 每个参数通过才算通过,相当于hasAllRoles()方法。 perms(权限):例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号, 并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"], 当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。 rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] , 其中method为post,get,delete等。 port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到 schemal://serverName:8081?queryString,其中schmal是协议http或https等, serverName是你访问的host,8081是url配置里port的端口,queryString是你访问的url里的?后面的参数。 authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证 ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查 */ // 详情参考shiro.web.filter源码
控制器类,登录 退出方法
LoginController.java
package com.controller; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.LockedAccountException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class LoginController { /** * 登录请求方法 * * @param username 用户名 * @param password 密码 * @return */ @PostMapping(value = "/login") public String loginPost(String username, String password) { /** * 使用Shiro进行认证操作 */ //获取Subject Subject subject = SecurityUtils.getSubject(); //封装用户数据 UsernamePasswordToken token = new UsernamePasswordToken(username, password); //是否记住我操作,这里我默认设置记住我 token.setRememberMe(true); //执行登录方法 try { subject.login(token); //登录成功操作 } catch (UnknownAccountException e) { //用户不存在 e.printStackTrace(); } catch (IncorrectCredentialsException e) { //用户名密码错误 e.printStackTrace(); } catch (LockedAccountException e) { e.printStackTrace(); //账号被禁用 } return null; } /** * 登出 * * @return */ @RequestMapping("/logout") public String logout() { Subject subject = SecurityUtils.getSubject(); subject.logout(); Session session = subject.getSession(); //情况session中的用户信息 session.removeAttribute("user"); //返回登录页 return "login"; } }