springboot 接入shiro
阿新 • • 發佈:2022-02-04
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。