写给我大聂哥
Apache Shiro™ is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, and session management. With Shiro’s easy-to-understand API, you can quickly and easily secure any application – from the smallest mobile applications to the largest web and enterprise applications.
Apache Shiro™是一个强大且易用的Java安全框架,能够用于身份验证、授权、加密和会话管理。Shiro拥有易于理解的API,您可以快速、轻松地获得任何应用程序——从最小的移动应用程序到最大的网络和企业应用程序。
简单来说就是:Shiro是apache的一个开源安全框架,作用就是实现用户身份认证、权限授权、加密、会话管理等功能。
官方说法
注意: Shiro不会去维护用户、维护权限,这些需要我们自己去设计/提供,然后通过相应的接口注入给Shiro
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!-- MySQL 连接驱动依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!-- spring boot 热部署 stat-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- spring boot 热部署 end -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
</configuration>
</plugin>
</plugins>
</build>
package com.lzl.practice.Util;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.List;
public class JacksonUtil {
public static String parseString(String body, String field) {
ObjectMapper mapper = new ObjectMapper();
JsonNode node = null;
try {
node = mapper.readTree(body);
JsonNode leaf = node.get(field);
if (leaf != null)
return leaf.asText();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static List<String> parseStringList(String body, String field) {
ObjectMapper mapper = new ObjectMapper();
JsonNode node = null;
try {
node = mapper.readTree(body);
JsonNode leaf = node.get(field);
if (leaf != null)
return mapper.convertValue(leaf, new TypeReference<List<String>>() {
});
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static Integer parseInteger(String body, String field) {
ObjectMapper mapper = new ObjectMapper();
JsonNode node = null;
try {
node = mapper.readTree(body);
JsonNode leaf = node.get(field);
if (leaf != null)
return leaf.asInt();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static List<Integer> parseIntegerList(String body, String field) {
ObjectMapper mapper = new ObjectMapper();
JsonNode node = null;
try {
node = mapper.readTree(body);
JsonNode leaf = node.get(field);
if (leaf != null)
return mapper.convertValue(leaf, new TypeReference<List<Integer>>() {
});
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static Boolean parseBoolean(String body, String field) {
ObjectMapper mapper = new ObjectMapper();
JsonNode node = null;
try {
node = mapper.readTree(body);
JsonNode leaf = node.get(field);
if (leaf != null)
return leaf.asBoolean();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static Short parseShort(String body, String field) {
ObjectMapper mapper = new ObjectMapper();
JsonNode node = null;
try {
node = mapper.readTree(body);
JsonNode leaf = node.get(field);
if (leaf != null) {
Integer value = leaf.asInt();
return value.shortValue();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static Byte parseByte(String body, String field) {
ObjectMapper mapper = new ObjectMapper();
JsonNode node = null;
try {
node = mapper.readTree(body);
JsonNode leaf = node.get(field);
if (leaf != null) {
Integer value = leaf.asInt();
return value.byteValue();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static <T> T parseObject(String body, String field, Class<T> clazz) {
ObjectMapper mapper = new ObjectMapper();
JsonNode node = null;
try {
node = mapper.readTree(body);
node = node.get(field);
return mapper.treeToValue(node, clazz);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static Object toNode(String json) {
if (json == null) {
return null;
}
ObjectMapper mapper = new ObjectMapper();
try {
JsonNode jsonNode = mapper.readTree(json);
return jsonNode;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
@Configuration
public class ShiroConfig {
//将自己的登录验证方式加入容器
//直接写return new AuthRealm()也是一样的,但是不要在下面的securityManager()方法中直接new AuthRealm()
//直接new的话我只能说好家伙,自己实例化对象之后该类就不会在springboot容器中了,
//这样就不能在AuthRealm类中autowired了
@Bean
public Realm AuthRealm() {
AuthRealm authRealm = new AuthRealm();
return authRealm;
}
//将自己配置的AuthRealm配置到securityManager中
@Bean
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(AuthRealm());
return securityManager;
}
//Filter工厂,设置对应的过滤条件和跳转条件
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String,String> map = new HashMap<String, String>();
//登出
map.put("/logout","logout");
//对所有用户认证
map.put("/**","authc");
//首页
shiroFilterFactoryBean.setSuccessUrl("/index");
//错误页面,认证不通过跳转
shiroFilterFactoryBean.setUnauthorizedUrl("/auth/error");
shiroFilterFactoryBean.setLoginUrl("/auth/login");//登录
shiroFilterFactoryBean.setSuccessUrl("/auth/index");
shiroFilterFactoryBean.setUnauthorizedUrl("/auth/403");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
//开启代码支持
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
shirFilter工厂里面的的logout、authc、anon都是拦截器。
拦截器链名定义
名字 | 名称 | 说明 |
---|---|---|
anon | 匿名拦截器 | 不需要登录就能访问,一般用于静态资源,或者移动端接口 |
authc | 登录拦截器 | 需要登录认证才能访问的资源 |
user | 用户拦截器 | 用户拦截器,用户已经身份验证 / 记住我登录的都可; |
logout | 登出拦截器 | 用户登出拦截器 |
public class AuthRealm extends AuthorizingRealm {
/***
* @Description: 这块是授权配置
* @Param: [principalCollection]
* @return: org.apache.shiro.authz.AuthorizationInfo
* @Author: lizelin
* @Date: 2021/5/13 0013 1:25
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
return info;
}
/***
* @Description: 这块是登录验证配置
* @Param: [token]
* @return: org.apache.shiro.authc.AuthenticationInfo
* @Author: lizelin
* @Date: 2021/5/13 0013 1:25
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//AuthenticationToken转成UsernamePasswordToken这样可以直接拿到用户名和密码
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String username = upToken.getUsername();
//判断用户名是否为aaa否则抛出异常完事密码错误
if(!username.equals("aaa")){
throw new UnknownAccountException("用户错误");
}
return new SimpleAuthenticationInfo(upToken.getUsername(), upToken.getPassword(), "ShiroReaml");
}
这里我只写了登录验证配置,判断用户名是否正确,简单测试一下,加入授权和密码验证明天再说今天困了。
@RestController
@RequestMapping("/auth")
public class AuthController {
/**
* @Description: 登录验证
* @Param: [body]
* @return: java.lang.Object
* @Author: Mr.Wang
* @Date: 2021/5/13 0013 1:50
*/
@PostMapping("/login")
public Object login(@RequestBody String body) {
String username = JacksonUtil.parseString(body, "username");
String password = JacksonUtil.parseString(body, "password");
//获取Subject
Subject subject = SecurityUtils.getSubject();
try {
//登录测试,就这一行代码
subject.login(new UsernamePasswordToken(username, password));
} catch (UnknownAccountException uae) {
return "用户帐号或密码不正确";
} catch (LockedAccountException lae) {
return "用户帐号已锁定不可用";
} catch (AuthenticationException ae) {
return "用户帐号已锁定不可用";
}
return "登录成功,账号名:"+username;
}
@PostMapping("/testAuthc")
public Object testAuthc() {
return "testAuthc";
}
@GetMapping("/401")
public Object page401() {
return "401";
}
@GetMapping("/index")
public Object pageIndex() {
return "index";
}
@GetMapping("/403")
public Object page403() {
return "index";
}
@GetMapping("/error")
public Object error() {
return "error";
}
}
简单的测试环境就搭好了,完事我们去测试。
简单的登陆用户名验证就完事了,然后写密码验证,权限,三方登录