已有Shiro可直接看第3步,修改第4步
改造后支持cookie鉴权以及header鉴权,其他方式可自行修改
本文基本无讲解,专注用法
这里假设已有User表,User对象,以及对应的数据库操作类
1.引入依赖
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.5.1</version> </dependency>
2.新建realm
继承org.apache.shiro.realm.AuthorizingRealm
类
实现doGetAuthenticationInfo(用户鉴权方法)
@Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken; String username = token.getPrincipal().toString();//获取用户名 String password = String.valueOf((char[]) token.getCredentials());//获取密码 User u = userRepository.getUserByUsername(username);//获取用户 if (u==null){ throw new AccountException("用户不存在"); } //这里简单讲解,实际应用需要加密密码 if (!password.equals(u.getPassword())){ throw new AccountException("密码不正确"); } //返回构建好的AuthInfo,第一个参数为用户主体,第二个为用户密码,第三个getName()即可 return new SimpleAuthenticationInfo(u,u.getPassword(),getName()); }
实现doGetAuthorizationInfo(获取用户角色权限方法)
@Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { User user = (User)SecurityUtils.getSubject().getPrincipal();//获取已登录的用户,肯定不为null,无需其他判断 SimpleAuthorizationInfo info =new SimpleAuthorizationInfo(); //info对象 setRoles用于设置用户角色权限,setStringPermissions设置角色的菜单权限(具体我也不知道怎么说了) //setObjectPermissions与setStringPermissions相同作用 return info; }
3.自定义SessionManager(重要!!!!)
没什么可说的 直接贴代码,主要作用就是添加sessionid获取位置,首先从header中获取,其次cookie
import org.apache.shiro.web.servlet.ShiroHttpServletRequest; import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; import org.apache.shiro.web.util.WebUtils; import org.springframework.util.StringUtils; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import java.io.Serializable; /** * @author 帝王攻Rainy * @name MySessionManager * @description * @date 2020/4/26 9:02 * @since 1.8 */ public class MySessionManager extends DefaultWebSessionManager { private static final String AUTHORIZATION = "Authorization"; private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request"; public MySessionManager(){ super(); } @Override protected Serializable getSessionId(ServletRequest request, ServletResponse response){ String id = WebUtils.toHttp(request).getHeader(AUTHORIZATION); if (!StringUtils.isEmpty(id)) { request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE); request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id); request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE); return id; } else { //否则按默认规则从cookie取sessionId return super.getSessionId(request, response); } } }
4.编写ShiroConfig
import com.luoyuer.vueblogbackend.security.filter.AuthcFilter; import com.luoyuer.vueblogbackend.security.filter.RolesFilter; import com.luoyuer.vueblogbackend.security.realm.MyRealm; import com.luoyuer.vueblogbackend.security.session.MySessionManager; import org.apache.shiro.session.mgt.SessionManager; 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.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.servlet.Filter; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; /** * @author 帝王攻Rainy * @name ShiroConfig * @description * @date 2020/4/26 9:08 * @since 1.8 */ @Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(org.apache.shiro.mgt.SecurityManager securityManager){ ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); bean.setSecurityManager(securityManager); //filterChainDefinitionMap的key是url,值是权限过滤器,具体用法请百度,这里不讲 Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/api/user/**","roles[user]"); filterChainDefinitionMap.put("/api/admin/**","roles[admin]"); bean.setFilterChainDefinitionMap(filterChainDefinitionMap); bean.setFilters(filterMap); return bean; } //注册securityManager @Bean public org.apache.shiro.mgt.SecurityManager securityManager(){ DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); manager.setSessionManager(sessionManager()); manager.setRealm(realm()); return manager; } //这里不能注册DefaultWebSessionManager,需要改为注册自己写的sessionManager,否则sessionid依旧获取不到 @Bean public SessionManager sessionManager(){ MySessionManager sessionManager = new MySessionManager(); return sessionManager; } //注册realm @Bean public MyRealm realm(){ MyRealm realm = new MyRealm(); return realm; } //开启shiro注解支持,如@RequiresPermissions,@RequiresRoles等等 @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor( @Qualifier("securityManager") org.apache.shiro.mgt.SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } }
到这里就基本结束了,但是shiro没有权限的返回值不是我们想要的(注解式的没有权限可以使用捕获异常来统一返回格式,在shiroFilterFactoryBean中定义的url需要重写Filter来解决
Authc拦截器,下面的new ReturnVO换为自己的
import com.fasterxml.jackson.databind.ObjectMapper; import com.luoyuer.vueblogbackend.model.ReturnVO; import org.apache.shiro.web.filter.authc.UserFilter; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import java.io.IOException; /** * @author 帝王攻Rainy * @name MyPermFilter * @description * @date 2020/4/26 17:34 * @since 1.8 */ public class AuthcFilter extends UserFilter { //重写回到主页方法 @Override protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException { response.setContentType("application/json; charset=utf-8"); response.getWriter().print(new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(new ReturnVO("没有权限",401))); } //重写没有权限方法 @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException { response.setContentType("application/json; charset=utf-8"); response.getWriter().print(new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(new ReturnVO("没有权限",401))); return false; } }
Roles拦截器同上,不过需要将继承的类改为org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
如需修改其他拦截器,重写相关拦截器即可
最后在ShiroConfig.shiroFilterFactoryBean中添加如下代码,用于替代原拦截器:
Map<String, Filter> filterMap = new HashMap<>(); filterMap.put("authc",new AuthcFilter()); filterMap.put("roles",new RolesFilter()); bean.setFilters(filterMap);
sessionid获取顺序:
1.从header中获取Authorization
的值
2.从cookie中获取JSESSIONID
的值
Comments | NOTHING