标签:request account tom except 操作 object 包含 成功 退出
就是分析需求。可以参考《Spring Boot实战之旅》。
<!--shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
首先要分析出表和表之间的关系,user表和role表的关系是多对多,role表和menu表的关系也是多对多。
@Entity
public class User implements Serializable {
@Id
@GeneratedValue
private Integer userId;
private String userName;
private String passWord;
@ManyToMany(fetch= FetchType.EAGER)
@JoinTable(name = "UserRole", joinColumns = { @JoinColumn(name = "userId") },
inverseJoinColumns ={@JoinColumn(name = "roleId") })
private List<Role> roleList;
//setter getter
}
@Entity
public class Role implements Serializable {
@Id
@GeneratedValue
private Integer roleId;
private String roleName;
@ManyToMany(fetch= FetchType.EAGER)
@JoinTable(name="RoleMenu",joinColumns={@JoinColumn(name="roleId")},inverseJoinColumns={@JoinColumn(name="menuId")})
private List<Menu> menuList;
@ManyToMany
@JoinTable(name="UserRole",joinColumns={@JoinColumn(name="roleId")},inverseJoinColumns={@JoinColumn(name="userId")})
private List<User> userList;
//setter getter
}
@Entity
public class Menu implements Serializable {
@Id
@GeneratedValue
private Integer menuId;
private String menuName;
@ManyToMany
@JoinTable(name="RoleMenu",joinColumns={@JoinColumn(name="menuId")},inverseJoinColumns={@JoinColumn(name="roleId")})
private List<Role> roleList;
//setter getter
}
创建一个JPA数据操作层,里面加入一个根据用户名查询用户的方法:
public interface UserRepository extends JpaRepository<User,Long> {
User findByUserName(String username);
}
创建一个 ShiroConfig,然后创建一个 shiroFilter方法。在 Shiro使用认证和授权时,其实都是通过 ShiroFilterFactoryBean设置一些Shiro的拦截器进行的,拦截器会以 LinkedHashMap的形式存储需要拦截的资源及链接,并且会按照顺序执行,其中键为拦截的资源或链接,值为拦截的形式(比如 authc:所有URL都必须认证通过才可以访问,anon:所有URL都可以匿名访问),在拦截的过程中可以使用通配符,比如/**为拦截所有,所以一般放在最下面。同时,可以通过ShiroFilterFactoryBean设置登录链接、未授权链接、登录成功跳转页等,这里设置的 shiroFilter方法内容如以下代码所示:
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//shiro拦截器
Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
//<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
//<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->
// 配置不被拦截的资源及链接
filterChainDefinitionMap.put("/static/**", "anon");
// 退出过滤器
filterChainDefinitionMap.put("/logout", "logout");
//配置需要认证权限的
filterChainDefinitionMap.put("/**", "authc");
// 默认寻找登录链接
shiroFilterFactoryBean.setLoginUrl("/login");
// 登录成功后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl("/index");
//未授权的跳转链接
shiroFilterFactoryBean.setUnauthorizedUrl("/401");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
//自定义身份认证Realm(包含用户名密码校验,权限校验等)
@Bean
public MyShiroRealm myShiroRealm(){
MyShiroRealm myShiroRealm = new MyShiroRealm();
return myShiroRealm;
}
@Bean
public SecurityManager securityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myShiroRealm());
return securityManager;
}
//开启shiro aop注解支持,不开启的话权限验证就会失效
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
//处理异常,当用户没有权限时设置跳转到401页面
@Bean(name="simpleMappingExceptionResolver")
public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() {
SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
//数据库异常处理
mappings.setProperty("DatabaseException", "databaseError");
//未经过认证
mappings.setProperty("UnauthorizedException","401");
// None by default
simpleMappingExceptionResolver.setExceptionMappings(mappings);
// No default
simpleMappingExceptionResolver.setDefaultErrorView("error");
// Default is "exception"
simpleMappingExceptionResolver.setExceptionAttribute("ex");
return simpleMappingExceptionResolver;
}
}
MyShiroRealm类代码如下:
@Configuration
public class MyShiroRealm extends AuthorizingRealm {
@Resource
private UserRepository userRepository;
//授权方法,主要用于获取角色的菜单权限
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
User userInfo = (User)principals.getPrimaryPrincipal();
for(Role role:userInfo.getRoleList()){
authorizationInfo.addRole(role.getRoleName());
for(Menu menu:role.getMenuList()){
authorizationInfo.addStringPermission(menu.getMenuName());
}
}
return authorizationInfo;
}
//认证方法,主要用于校验用户名和密码
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException {
//获得当前用户的用户名
String username = (String)token.getPrincipal();
//根据用户名查询用户
User user = userRepository.findByUserName(username);
if(user == null){
return null;
}
//校验用户名密码是否正确
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
user,
user.getPassWord(),
getName()
);
return authenticationInfo;
}
}
注意既然是配置类,都要在类上加上@Configuration,这种默认操作一开始就加后面容易忘。
这就不多说了。测试而已,很简单。
@Controller
public class ShiroController {
@GetMapping({"/","/index"})
public String index(){
return"index";
}
@GetMapping("/401")
public String unauthorizedRole(){
return "401";
}
@GetMapping("/delete")
@RequiresRoles("admin")
public String delete(){
return "delete";
}
@GetMapping("/select")
@RequiresPermissions("select")
public String select(){
return "select";
}
@RequestMapping("/login")
public String login(HttpServletRequest request, Map<String, Object> map){
// 如果登录失败的话,那么就从HttpServletRequest中获取shiro处理的异常信息,获取shiroLoginFailure就是shiro异常类的全名。
String exception = (String) request.getAttribute("shiroLoginFailure");
String msg = "";
//根据异常判断错误类型
if (exception != null) {
if (UnknownAccountException.class.getName().equals(exception)) {
msg = "用户名不存在!";
} else if (IncorrectCredentialsException.class.getName().equals(exception)) {
msg = "密码错误!";
} else {
msg = exception;
}
}
map.put("msg", msg);
return "/login";
}
@GetMapping("/logout")
public String logout(){
return "/login";
}
}
标签:request account tom except 操作 object 包含 成功 退出
原文地址:https://www.cnblogs.com/xc-xinxue/p/12417146.html