1. shiro的简单配置
1.1 pom坐标
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
1.2 用户验证与授权
package com.zp.shirodemo.config;
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.subject.PrincipalCollection;
import java.util.HashSet;
import java.util.Set;
/**
* @ClassName Realm
*/
public class CustomRealm extends AuthorizingRealm {
/**
* 获取身份验证信息
* Shiro中,最终是通过 Realm 来获取应用程序中的用户、角色及权限信息的。
* @param authenticationToken 用户身份信息 token
* @return 返回封装了用户信息的 AuthenticationInfo 实例
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("————身份认证方法————");
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String username = token.getUsername();
//通过用户名获取 用户信息
UserBean userBean=new UserBean("1",username, "123456");
if (null == userBean) {
//用户不存在,抛出UnknownAccountException异常
throw new UnknownAccountException();
} else{
//用户纯在进行验证
return new SimpleAuthenticationInfo(userBean,userBean.getPassword(),ByteSource.Util.bytes(userBean.getName()+"salt"),getName());
}
}
/**
* 获取授权信息
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("————权限认证————");
UserBean username = (UserBean) SecurityUtils.getSubject().getPrincipal();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//获得该用户角色,权限,可从数据库中查出
info.setRoles(Set<String> roles);
info.setStringPermissions(Set<String> permissions);
return info;
}
}
1.3 shiro相关配置
package com.zp.shirodemo.config;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
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.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必须设置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// setLoginUrl 如果不设置值,默认会自动寻找Web工程根目录下的"/login.jsp"页面 或 "/login" 映射
shiroFilterFactoryBean.setLoginUrl("/main/toLogin");
// 设置无权限时跳转的 url;
shiroFilterFactoryBean.setUnauthorizedUrl("/main/403");
// 设置拦截器
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
//游客,开发权限
filterChainDefinitionMap.put("/main/guest/**", "anon");
// //用户,需要角色权限 “user”
// filterChainDefinitionMap.put("/main/user/**", "roles[user]");
// //管理员,需要角色权限 “admin”
// filterChainDefinitionMap.put("/main/admin/**", "roles[admin]");
//开放登陆接口
filterChainDefinitionMap.put("/main/toLogin", "anon");
//开放登陆接口
filterChainDefinitionMap.put("/main/login", "anon");
//其余接口一律拦截
//主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
System.out.println("Shiro拦截器工厂类注入成功");
return shiroFilterFactoryBean;
}
/**
* 注入 securityManager
*/
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 设置realm.
securityManager.setRealm(customRealm());
return securityManager;
}
/**
* 自定义身份认证 realm;
* <p>
* 必须写这个类,并加上 @Bean 注解,目的是注入 CustomRealm,
* 否则会影响 CustomRealm类 中其他类的依赖注入
*/
@Bean
public CustomRealm customRealm() {
return new CustomRealm();
}
}
anon:例子/admins/**=anon 表示可以匿名使用,不需要验证及授权就可访问
authc:例如/user/**=authc 表示需要认证(登录)才能使用
user:例如/user/**=user 表示必须存在用户, 身份认证通过或通过记住我认证通过的可以访问,当登入操作时不做检查
authcBasic:例如/user/**=authcBasic 表示httpBasic认证
roles:例子/user/**=/user/**=roles["admin,guest"], 设置角色,单个参数可省略引号,,每个参数通过才算通过
perms:例子/user/**=perms["add:*,mod:*"],设置权限,单个参数可省略引号,当有多个参数时必须每个参数都通过才通过。
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里的?后面的参数。
ssl:例子/admins/user/**=ssl 表示安全的url请求,协议为https
注:
anon,authcBasic,auchc,user是认证过滤器,
perms,roles,ssl,rest,port是授权过滤器
1.4 登录接口
@RequestMapping("/login")
public String login(Model model, HttpServletRequest request, HttpServletResponse response){
response.setHeader("root", request.getContextPath());
String userName = request.getParameter("username");
String password = request.getParameter("password");
// 1.获取Subject
Subject subject = SecurityUtils.getSubject();
// 2.封装用户数据
UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
// 3.执行登录方法
try{
//有记住功能的可通过setRememberMe设置
//token.setRememberMe(true);
//登录并定向到首页
subject.login(token);
return "redirect:/main/toIndex";
} catch (UnknownAccountException e){
e.printStackTrace();
request.setAttribute("msg","用户名/密码错误");
return "login";
} catch (IncorrectCredentialsException e){
request.setAttribute("msg","用户名/密码错误");
return "login";
}
}
1.5 退出接口
@RequestMapping("/logout")
public String logout(){
Subject subject = SecurityUtils.getSubject();
if (subject != null) {
subject.logout();
}
return "redirect:/login";
}
2. shiro的其他配置
2.1 注解整合
/**
* 开启Shiro的注解
* @return
*/
@Bean
@DependsOn({"lifecycleBeanPostProcessor"})
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
return authorizationAttributeSourceAdvisor;
}
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
return new LifecycleBeanPostProcessor();
}
/**
* @Description //权限注解无权限时的视图配置
**/
@Bean
public SimpleMappingExceptionResolver simpleMappingExceptionResolver(){
SimpleMappingExceptionResolver simpleMappingExceptionResolver=new SimpleMappingExceptionResolver();
Properties properties=new Properties();
properties.put("org.apache.shiro.authz.UnauthorizedException","/main/403");
simpleMappingExceptionResolver.setExceptionMappings(properties);
return simpleMappingExceptionResolver;
}
2.2 jsp整合
页面引入
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
2.3 freemarker整合
引用pom坐标:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>net.mingsoft</groupId>
<artifactId>shiro-freemarker-tags</artifactId>
<version>0.1</version>
</dependency>
添加配置bean :
/**
*添加了这个bean后,在application.properties中的配置会失效,默认配置也会失效
**/
@Bean
public FreeMarkerConfigurer freeMarkerConfigurer() throws IOException, TemplateException {
FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer();
freeMarkerConfigurer.setTemplateLoaderPath("classpath:templates/");
freemarker.template.Configuration configuration = freeMarkerConfigurer.createConfiguration();
configuration.setDefaultEncoding("UTF-8");
//这里可以添加其他共享变量 比如sso登录地址
configuration.setSharedVariable("shiro", new ShiroTags());
freeMarkerConfigurer.setConfiguration(configuration);
return freeMarkerConfigurer;
}
模板中应用:
- <@shiro.principal property="name" /> 输出当前用户信息,通常为登录帐号信息
- <@shiro.guest> </@shiro.guest> 未认证(包含未记住)的用户
- <@shiro.user> </@shiro.user> 认证通过或已记住的用户
- <@shiro.authenticated></@shiro.authenticated> 已认证通过的用户。不包含已记住的用户
- <@shiro.notAuthenticated></@shiro.notAuthenticated> 未认证通过的用户。与authenticated标签相对
- <@shiro.hasRole name=”admin”></@shiro.hasRole> 验证当前用户是否属于该角色
- <@shiro.hasAnyRoles name="admin,user"></@shiro.hasAnyRoles>验证当前用户是否属于这些角色中的任何一个
- <@shiro.hasPermission name="/order:*"></@shiro.hasPermission> 验证当前用户是否拥有该权限
- <@shiro.lacksRole name="admin"></@shiro.lacksRole> 验证当前用户不属于该角色
- <@shiro.lacksPermission name="/order:*"></@shiro.lacksPermission> 验证当前用户不拥有某种权限
2.4 thymeleaf整合
引用pom坐标及规定版本:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<!--放在dependencies标签外-->
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<thymeleaf.version>3.0.0.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.0.0</thymeleaf-layout-dialect.version>
</properties>
配置文件
#指定模板所在的目录
spring.thymeleaf.prefix= classpath:/templates/
#检查模板路径是否存在
spring.thymeleaf.check-template-location= true
#是否缓存,开发模式下设置为false,避免改了模板还要重启服务器,线上设置为true,可以提高性能。
spring.thymeleaf.cache= false
spring.thymeleaf.suffix= .html
#与Servlet中设置输出对应属性效果一致。
spring.thymeleaf.encoding= UTF-8
spring.thymeleaf.content-type= text/html
spring.thymeleaf.mode= HTML5
添加配置bean
@Bean(name = "shiroDialect")
public ShiroDialect shiroDialect() {
return new ShiroDialect();
}
模板中应用:
引入 <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
应用在要控制显示的标签中:例如:<a shiro:hasPermission="add" href="#">新增</a>
控制详解:
- shiro:guest="" 验证当前用户是否为“访客”,即未认证(包含未记住)的用户。
- shiro:user="" 认证通过或已记住的用户
- shiro:authenticated="" 已认证通过的用户。不包含已记住的用户,这是与user标签的区别所在。
- shiro:notAuthenticated="" 未认证通过用户,与authenticated相对应。与guest的区别是,该含已记住用户。
- shiro:hasRole="admin" 验证当前用户是否属于该角色。
- shiro:lacksRole="developer" 与hasRole标签逻辑相反,当用户不属于该角色时验证通过。
- shiro:hasAllRoles="developer, 2" 验证当前用户是否属于以下所有角色。
- shiro:hasAnyRoles="admin, vip, developer,1" 验证当前用户是否属于以下任意一个角色。
- shiro:hasPermission="userInfo:add" 验证当前用户是否拥有指定权限。
- shiro:hasAllPermissions="userInfo:view, userInfo:add" 验证当前用户是否拥有以下所有角色。
- shiro:hasAnyPermissions="userInfo:view, userInfo:del" 验证当前用户是否拥有以下任意一个权限。