添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<!-- shiro-spring -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>
shiro配置类
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 设置securityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 登录的url
shiroFilterFactoryBean.setLoginUrl("/login");
// 登录成功后跳转的url
shiroFilterFactoryBean.setSuccessUrl("/index");
// 未授权url
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
// 定义filterChain,静态资源不拦截
filterChainDefinitionMap.put("/css/**", "anon");
filterChainDefinitionMap.put("/js/**", "anon");
filterChainDefinitionMap.put("/fonts/**", "anon");
filterChainDefinitionMap.put("/img/**", "anon");
// druid数据源监控页面不拦截
filterChainDefinitionMap.put("/druid/**", "anon");
// 配置退出过滤器,其中具体的退出代码Shiro已经替我们实现了
filterChainDefinitionMap.put("/logout", "logout");
filterChainDefinitionMap.put("/", "anon");
// 除上以外所有url都必须认证通过才可以访问,未通过认证自动访问LoginUrl
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public SecurityManager securityManager(){
// 配置SecurityManager,并注入shiroRealm
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(shiroRealm());
return securityManager;
}
@Bean
public ShiroRealm shiroRealm(){
// 配置Realm,需自己实现
ShiroRealm shiroRealm = new ShiroRealm();
return shiroRealm;
}
}
注意filterChain基于短路机制,即最先匹配原则
/user/**=anon
/user/aa=authc 永远不会执行
自定义Realm
自定义realm需要继承AuthorizingRealm。实现doGetAuthorizationInfo(用于授权)与doGetAuthenticationInfo(用于认证)方法。
public class ShiroRealm extends AuthorizingRealm {
@Autowired
private UserMapper userMapper;
/**
* 获取用户角色和权限
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
return null;
}
/**
* 登录认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 获取用户输入的用户名和密码
String userName = (String) token.getPrincipal();
String password = new String((char[]) token.getCredentials());
System.out.println("用户" + userName + "认证-----ShiroRealm.doGetAuthenticationInfo");
// 通过用户名到数据库查询用户信息
User user = userMapper.findByUserName(userName);
if (user == null) {
throw new UnknownAccountException("用户名或密码错误!");
}
if (!password.equals(user.getPassword())) {
throw new IncorrectCredentialsException("用户名或密码错误!");
}
if (user.getStatus().equals("0")) {
throw new LockedAccountException("账号已被锁定,请联系管理员!");
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
return info;
}
controller
登录验证功能实现
@PostMapping("/login")
@ResponseBody
public ResponseBo login(String username, String password) {
// 密码MD5加密
password = MD5Utils.encrypt(username, password);
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
// 获取Subject对象
Subject subject = SecurityUtils.getSubject();
try {
subject.login(token);
return ResponseBo.ok();
} catch (UnknownAccountException e) {
return ResponseBo.error(e.getMessage());
} catch (IncorrectCredentialsException e) {
return ResponseBo.error(e.getMessage());
} catch (LockedAccountException e) {
return ResponseBo.error(e.getMessage());
} catch (AuthenticationException e) {
return ResponseBo.error("认证失败!");
}
}