2019年7月16
最近在学习shiro关于权限控制这一块,对shiro理解了一些,有一部分知识点还没有弄清楚,先记录一部分的内容,之后会加以补充,直接上代码
1、pom.xm代码
<properties>
<java.version>1.8</java.version>
<mybatisplus.version>3.0.7.1</mybatisplus.version>
<shiro.version>1.4.0</shiro.version>
</properties>
<dependencies>
<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>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
</dependencies>
2、ShiroConfig 配置文件,对拦截器的配置,自定义拦截类,也可以自定义记住密码类以及缓存类,这里面有一个坑,那就是SecurityManager类默认导入的类,有问题,需要自己引入import org.apache.shiro.mgt.SecurityManager;
OAuth2Realm类是自己定义的类,需要实现AuthorizingRealm
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Shiro配置
*
* @author Mark sunlightcs@gmail.com
*/
@Configuration
public class ShiroConfig {
@Bean("securityManager")
public SecurityManager securityManager(OAuth2Realm oAuth2Realm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(oAuth2Realm);
securityManager.setRememberMeManager(null);
return securityManager;
}
@Bean("shiroFilter")
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
Map<String, String> filterMap = new LinkedHashMap<>();
//oauth过滤
Map<String, Filter> filters = new HashMap<>();
filters.put("oauth2", new OAuth2Filter());
shiroFilter.setFilters(filters);
/* filterMap.put("/api/**", "roles[admin]");*/
filterMap.put("/**", "oauth2");
shiroFilter.setFilterChainDefinitionMap(filterMap);
return shiroFilter;
}
@Bean("lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
}
3、OAuth2Realm自定义类。重写用户身份认证方法和权限验证方法
@Component
public class OAuth2Realm extends AuthorizingRealm {
@Autowired
private ShiroService shiroService;
/**
* 授权(验证权限时调用)
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("————权限认证————");
SysUserEntity user = (SysUserEntity)principals.getPrimaryPrincipal();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//获得该用户角色
Set<String> set = new HashSet<>();
//需要将 role 封装到 Set 作为 info.setRoles() 的参数
set.add("user");
//设置该用户拥有的角色
info.setRoles(set);
return info;
}
/**
* 认证(登录时调用)
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("————身份认证方法————");
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
// 从数据库获取对应用户名密码的用户
String userName = token.getUsername();
SysUserEntity s = shiroService.getPassword(userName);
if (null == s.getPassword()) {
throw new AccountException("用户名不正确");
} else if (! s.getPassword().equals(new String((char[]) token.getCredentials()))) {
throw new AccountException("密码不正确");
}
return new SimpleAuthenticationInfo(token.getPrincipal(), s.getPassword(), getName());
}
}
4、自定义拦截类 ,在shiroConfig类中加入该拦截类,当需要走该拦截类时,会实现onAccessDenied方法
OAuth2Filter
5、其他工具类。可有可无,只是为了方便OAuth2Token
public class OAuth2Token implements AuthenticationToken {
private String token;
public OAuth2Token(String token){
this.token = token;
}
@Override
public String getPrincipal() {
return token;
}
@Override
public Object getCredentials() {
return token;
}
}
6、controller方法(登录的controller)==验证权限这一块,没走通,不知道为什么没有走验证权限这个方法,如果密码正确,则返回login方法里的return信息,如果密码不正确或者用户名不正确,则走身份验证方法的异常类,
if (null == s.getPassword()) {
throw new AccountException("用户名不正确");
} else if (! s.getPassword().equals(new String((char[]) token.getCredentials()))) {
throw new AccountException("密码不正确");
}
如果用户名不正确,用Postman跑接口时,会返回用户名不正确的信息,如果密码不正确,则返回密码不正确的信息。
@RestController
@RequestMapping("/api")
public class LoginController {
@Autowired
private ShiroService shiroService;
@RequestMapping(value = "/notLogin", method = RequestMethod.GET)
public String notLogin() {
return "您尚未登陆!";
}
@RequestMapping(value = "/notRole", method = RequestMethod.GET)
public String notRole() {
return "您没有权限!";
}
@RequestMapping(value = "/logout", method = RequestMethod.GET)
public String logout() {
Subject subject = SecurityUtils.getSubject();
//注销
subject.logout();
return "成功注销!";
}
/**
* 登陆
*
* @param username 用户名
* @param password 密码
*/
@RequestMapping(value = "/login", method = RequestMethod.GET)
@RequiresPermissions("generator:stuhonor:save")
public String login(String username, String password) {
// 从SecurityUtils里边创建一个 subject
Subject subject = SecurityUtils.getSubject();
// 在认证提交前准备 token(令牌)
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
// 执行认证登陆
subject.login(token);
System.out.println(subject.getPreviousPrincipals());
System.out.println(subject.getPrincipal());//获取用户名
System.out.println(subject.getPrincipals());//获取用户名
subject.getSession().setAttribute("username",subject.getPrincipals());
System.out.println(subject.getSession().getAttribute("username"));
String role="admin";
//根据权限,指定返回数据
if ("user".equals(role)) {
return "欢迎登陆";
}
if ("admin".equals(role)) {
return "欢迎来到管理员页面";
}
return "权限错误!";
}
}