1、建表、建实体类、service、mapper等,目的是查询用户信息和角色信息
查看代码
-- 三张表,二张关系表
create table if not exists sys_permissions
(
id int auto_increment comment '编号'
primary key,
permission varchar(100) null comment '权限编号',
description varchar(100) null comment '权限描述',
rid int null comment '此权限关联角色的id',
available int default 0 null comment '是否锁定',
constraint idx_sys_permissions_permission
unique (permission)
);
create table if not exists sys_roles
(
id int auto_increment comment '角色编号'
primary key,
role varchar(100) null comment '角色名称',
description varchar(100) null comment '角色描述',
pid int null comment '父节点',
available int default 0 null comment '是否锁定',
constraint idx_sys_roles_role
unique (role)
);
create table if not exists sys_roles_permissions
(
role_id int null comment '角色编号',
permission_id int null comment '权限编号'
);
create table if not exists sys_users
(
id int auto_increment comment '编号'
primary key,
username varchar(100) null comment '用户名',
password varchar(100) null comment '密码',
salt varchar(100) null comment '盐值',
role_id varchar(50) null comment '角色列表',
locked int default 0 null comment '是否锁定',
constraint idx_sys_users_username
unique (username)
);
create table if not exists sys_users_roles
(
user_id int null comment '用户编号',
role_id int null comment '角色编号'
);
2、pom
<!-- shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.6.0</version>
</dependency>
3、 CustomRealm:自定义Realm用于查询用户的角色和权限信息并保存到权限管理器
import com.pingan.domain.login.Permissions;
import com.pingan.domain.login.Role;
import com.pingan.domain.login.User;
import com.pingan.servcie.LoginService;
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 org.springframework.util.ObjectUtils;
public class CustomRealm extends AuthorizingRealm {
@Autowired
private LoginService loginService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取登录用户名
String name = (String) principalCollection.getPrimaryPrincipal();
//查询用户名称
User user = loginService.getUserByName(name);
//添加角色和权限
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
//添加角色
for (Role role : user.getRoleSet()) {
simpleAuthorizationInfo.addRole(role.getRoleName());
//添加权限
for (Permissions permissions : role.getPermissionSet()) {
simpleAuthorizationInfo.addStringPermission(permissions.getPermissionsName());
}
}
return simpleAuthorizationInfo;
}
//认证 返回null 或者SimpleAuthenticationInfo抛异常都算认证失败
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
if (ObjectUtils.isEmpty(authenticationToken.getPrincipal())){
return null;
}
String name = authenticationToken.getPrincipal().toString();
User user = loginService.getUserByName(name);
if (user == null) {
return null;
} else {
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name, user.getPassword().toString(), getName());
return simpleAuthenticationInfo;
}
}
}
4、ShiroConfig:shiro的配置类
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
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.LinkedHashMap;
@Configuration
public class ShiroConfig {
// 授权所用配置
@Bean
@ConditionalOnMissingBean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
//将自定义的验证方式加入容器
@Bean
public CustomRealm customRealm() {
CustomRealm customRealm = new CustomRealm();
return customRealm;
}
// 设置session过期时间
@Bean(name = "sessionManager")
public DefaultWebSessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
// 设置session过期时间10s
sessionManager.setGlobalSessionTimeout(10*1000L);
return sessionManager;
}
//权限管理,配置主要是Realm的管理认证
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
defaultWebSecurityManager.setRealm(customRealm());
defaultWebSecurityManager.setSessionManager(sessionManager());
return defaultWebSecurityManager;
}
//Filter工厂,设置对应的过滤条件和跳转条件
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
LinkedHashMap<String, String> map = new LinkedHashMap<>();
// 不拦截的路径
// swagger
map.put("/swagger-ui.html", "anon");
map.put("/swagger/**", "anon");
map.put("/swagger-resources/**", "anon");
map.put("/v2/**", "anon");
map.put("/webjars/**", "anon");
map.put("/configuration/**", "anon");
map.put("/doc.html","anon");
// 其它 anon 代表不拦截
map.put("/parent/*", "anon");
//登出 并清理seesion?登出后需要重新登陆
map.put("/logout", "logout");
// 拦截所有路径(除了不拦截的)
map.put("/**", "authc");
shiroFilterFactoryBean.setLoginUrl("/testLogin");
shiroFilterFactoryBean.setSuccessUrl("/index");
shiroFilterFactoryBean.setUnauthorizedUrl("/error");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
// 使授权注解起作用
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
// 自定义密码加密解密方式
// 在 myRealm重写这个方法设置新较验类 CustomCredentialsMatcher
@Override
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
CustomCredentialsMatcher customCredentialsMatcher = new CustomCredentialsMatcher();
super.setCredentialsMatcher(customCredentialsMatcher);
}
}
密码较验类
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import org.springframework.util.StringUtils;
// 自定义密码较验方式 写完这个类后要在自定义类MyRealm里重写 setCredentialsMatcher
public class CustomCredentialsMatcher extends SimpleCredentialsMatcher {
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
String username = usernamePasswordToken.getUsername();
String password = String.valueOf(usernamePasswordToken.getPassword());
String host = usernamePasswordToken.getHost();
System.out.println("host = " + host);
if (username.equals("root")) {
System.out.println("dddd = ----------" );
return true;
}
System.out.println(username+"============");
System.out.println("password = " + password);
return false;
// return super.doCredentialsMatch(token, info);
}
}
5、登陆Controller
@RestController
public class LoginController {
@Autowired
private UserMapper userMapper;
@GetMapping("/login")
private Object login(@RequestParam("username") String username, @RequestParam("password")String password, HttpServletRequest request) {
String ipAddress = getIpAddress(request);
// 调用shiro 传入username,password,ip (ip可传可不传)
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username,password,ipAddress);
try {
subject.login(usernamePasswordToken);
} catch (AuthenticationException e) {
e.printStackTrace();
return "登陆失败";
}
return "登陆成功啦啦啦啦";
}
//通过request取到ip地址
private static String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("X-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}
6、在对应用controller方法 或者service方法上加注解
@RequiresRoles
例如:@RequiresRoles(“aRoleName”);
void someMethod();
如果subject中有aRoleName角色才可以访问方法someMethod。如果没有这个权限则会抛出异常AuthorizationException。
@RequiresPermissions
例如: @RequiresPermissions({“file:read”, “write:aFile.txt”} )
void someMethod();
要求subject中必须同时含有file:read和write:aFile.txt的权限才能执行方法someMethod()。否则抛出异常AuthorizationException。