http://shiro.apache.org/
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.
一、引入依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.6.0</version>
</dependency>
二、建立必要实体
Permission
package springboot.domain;
import lombok.Data;
@Data
public class Permission {
private String id;
private String permissionName;
}
Role
package springboot.domain;
import lombok.Data;
import java.util.Set;
@Data
public class Role {
private String id;
private String roleName;
private Set<Permission> permissions;
}
TUser
package springboot.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.Date;
import java.util.Set;
/**
* <p>
* 后台管理用户表
* </p>
*
* @author duantingwei
* @since 2020-07-16
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class TUser extends Model {
private static final long serialVersionUID = 1L;
/**
* 账号
*/
@TableId
private String username;
/**
* 密码
*/
private String password;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
/**
* 表的后缀(年月) 按月分表
*/
@TableField(exist = false)
private String date;
/**
* 用户对应的角色集合
*/
@TableField(exist = false)
private Set<Role> roles;
}
三、建表,表中插入数据
-- auto-generated definition
create table t_user
(
username varchar(64) not null
primary key,
password varchar(64) not null,
create_time datetime not null,
update_time datetime null
);
四、写自定义Realm
TUserRealm
package springboot.config;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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 org.springframework.beans.factory.annotation.Autowired;
import springboot.domain.Permission;
import springboot.domain.Role;
import springboot.domain.TUser;
import springboot.service.TUserService;
public class TUserRealm extends AuthorizingRealm {
@Autowired
private TUserService tUserService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取登录用户名
String name = (String) principalCollection.getPrimaryPrincipal();
TUser tUser = tUserService.getById(name);
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
for(Role role: tUser.getRoles()){
simpleAuthorizationInfo.addRole(role.getRoleName());
for(Permission permission:role.getPermissions()){
simpleAuthorizationInfo.addStringPermission(permission.getPermissionName());
}
}
return simpleAuthorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
if(authenticationToken.getPrincipal()==null){
return null;
}
//获取用户信息
String name = authenticationToken.getPrincipal().toString();
TUser tUser = tUserService.getById(name);
if(tUser==null){
return null;
}else {
//这里验证authenticationToken和simpleAuthenticationInfo的信息
return new SimpleAuthenticationInfo(name, tUser.getPassword(), getName());
}
}
}
五、写配置类,装配相关类到容器
package springboot.config;
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.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class ShiroConfig {
@Bean
@ConditionalOnMissingBean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
defaultAAP.setProxyTargetClass(true);
return defaultAAP;
}
//将自己的验证方式加入容器
@Bean
public TUserRealm myShiroRealm() {
TUserRealm tUserRealm = new TUserRealm();
return tUserRealm;
}
//权限管理,配置主要是Realm的管理认证
@Bean
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
return securityManager;
}
//Filter工厂,设置对应的过滤条件和跳转条件
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> map = new HashMap<>();
//登出
map.put("/logout", "logout");
//对所有用户认证
map.put("/**", "authc");
//登录
shiroFilterFactoryBean.setLoginUrl("/login");
//首页
shiroFilterFactoryBean.setSuccessUrl("/index");
//错误页面,认证不通过跳转
shiroFilterFactoryBean.setUnauthorizedUrl("/error");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
六、写登录接口
@GetMapping("/login")
public String login(TUser tUser) {
if (StringUtils.isEmpty(tUser.getUsername()) || StringUtils.isEmpty(tUser.getPassword())) {
return "请输入用户名和密码!";
}
//用户认证信息
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(
tUser.getUsername(),
tUser.getPassword()
);
try {
//进行验证,这里可以捕获异常,然后返回对应信息
subject.login(usernamePasswordToken);
// subject.checkRole("admin");
// subject.checkPermissions("query", "add");
} catch (UnknownAccountException e) {
log.error("用户名不存在!", e);
return "用户名不存在!";
} catch (AuthenticationException e) {
log.error("账号或密码错误!", e);
return "账号或密码错误!";
} catch (AuthorizationException e) {
log.error("没有权限!", e);
return "没有权限";
}
return "login success";
}
八、登录后操作接口可以配置权限
@RequiresRoles("admin")
@GetMapping("/admin")
public String admin() {
return "admin success!";
}
@RequiresPermissions("query")
@GetMapping("/index")
public String index() {
return "index success!";
}
@RequiresPermissions("add")
@GetMapping("/add")
public String add() {
return "add success!";
}
测试效果