SpringBoot学习-简单shiro权限控制

来源:互联网 发布:淘宝买家真实福利图 编辑:程序博客网 时间:2024/06/06 05:38

前面介绍了很多基础设置的搭建方法,现在在前面的基础上,我们利用shiro来实现简单的登录及权限控制(只是简单的shiro集成,更细颗粒的shiro权限控制方法可以自己去学习shiro相关功能实现)。
框架基础:前面搭建的基础框架SpringBoot+JPA+MySQL
第一步:maven引入Jar包

<!-- shiro权限控制框架 --><dependency>    <groupId>org.apache.shiro</groupId>    <artifactId>shiro-spring</artifactId>    <version>1.3.2</version></dependency>

第二步:前端登录页设计及方法
这里写图片描述
登录页代码就不贴了,自己弄个简单的登录页测试一下就行
第三步:后端设计
这里写图片描述

Shiro配置类:

package com.example.demo.shiro;import org.apache.shiro.authc.credential.CredentialsMatcher;import org.apache.shiro.authc.credential.HashedCredentialsMatcher;import org.apache.shiro.mgt.SecurityManager;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 java.util.LinkedHashMap;import java.util.Map;/** * Created by John.Zhang on 2017/10/10. */@Configurationpublic class ShiroConfig {    /**     * ShiroFilterFactoryBean 处理拦截资源文件问题。     * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在     * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager     *     * Filter Chain定义说明 1、一个URL可以配置多个Filter,使用逗号分隔 2、当设置多个过滤器时,全部验证通过,才视为通过     * 3、部分过滤器可指定参数,如perms,roles     *     */    @Bean    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();        // 必须设置 SecurityManager        shiroFilterFactoryBean.setSecurityManager(securityManager);        // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面        shiroFilterFactoryBean.setLoginUrl("/");        // 未授权界面;//        shiroFilterFactoryBean.setUnauthorizedUrl("/403");        // 拦截器.        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();        // 配置不会被拦截的链接 顺序判断        filterChainDefinitionMap.put("/css/**", "anon");        filterChainDefinitionMap.put("/img/**", "anon");        filterChainDefinitionMap.put("/js/**", "anon");        filterChainDefinitionMap.put("/login", "anon");        // 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了        filterChainDefinitionMap.put("/logout", "logout");        // <!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;        // <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->        filterChainDefinitionMap.put("/**", "authc");        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);        System.out.println("Shiro拦截器工厂类注入成功");        return shiroFilterFactoryBean;    }    @Bean    public SecurityManager securityManager() {        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();        // 设置realm.        securityManager.setRealm(myShiroRealm());        return securityManager;    }    /**     * 身份认证realm;      *     * @return     */    @Bean    public ShiroRealm myShiroRealm() {        ShiroRealm myShiroRealm = new ShiroRealm();        myShiroRealm.setCredentialsMatcher(credentialsMatcher());        return myShiroRealm;    }    /**     * 凭证匹配器(用于加密密码使用,如不需要可以去除相关信息)     */    @Bean    public CredentialsMatcher credentialsMatcher(){        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher("MD5");        credentialsMatcher.setHashIterations(2);        return credentialsMatcher;    }}

自定义认证:

package com.example.demo.shiro;import com.example.demo.entities.Permission;import com.example.demo.entities.Role;import com.example.demo.entities.User;import com.example.demo.service.UserSevice;import org.apache.shiro.authc.*;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.apache.shiro.util.ByteSource;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import java.util.ArrayList;import java.util.List;public class ShiroRealm extends AuthorizingRealm {    private Logger logger = LoggerFactory.getLogger(ShiroRealm.class);    @Autowired    private UserSevice userSevice;    /**     * 登录认证     *     * @param authenticationToken     * @return     * @throws AuthenticationException     */    @Override    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;        logger.info("验证当前Subject时获取到token为:" + token.toString());        //查出是否有此用户        User hasUser = userSevice.findByName(token.getUsername());        if (hasUser != null) {            if(hasUser.getIsLocked() != null && hasUser.getIsLocked().equals(User.IsLocked.LOCKED))            {                throw new LockedAccountException("用户已被锁定,无法登录");            }            List<Role> rlist = userSevice.findRolesByUid(hasUser.getId());//获取用户角色            List<Permission> plist = userSevice.findPermissionsByUid(hasUser.getId());//获取用户权限            List<String> roles = new ArrayList<>();            List<String> permissions = new ArrayList<>();            for(Role role : rlist){                roles.add(role.getName());            }            for(Permission permission : plist){                permissions.add(permission.getName());            }            hasUser.setRoleList(roles);            hasUser.setPermissionList(permissions);//            Session session = SecurityUtils.getSubject().getSession();//            session.setAttribute("user", hasUser);//成功则放入session            // 若存在,将此用户存放到登录认证info中,无需自己做密码对比,Shiro会为我们进行密码对比校验            return new SimpleAuthenticationInfo(hasUser, hasUser.getPassword(),ByteSource.Util.bytes(hasUser.getSalt()), getName());        }else {            throw new UnknownAccountException("用户不存在");        }    }    /**     * 权限认证     *     * @param principalCollection     * @return     */    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {        logger.info("##################执行Shiro权限认证##################");        User user = (User) principalCollection.getPrimaryPrincipal();//        //到数据库查是否有此对象//        User user = null;// 实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法//        user = userMapper.findByName(loginName);        if (user != null) {            //权限信息对象info,用来存放查出的用户的所有的角色(role)及权限(permission)            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();            //用户的角色集合            info.addRoles(user.getRoleList());            //用户的权限集合            info.addStringPermissions(user.getPermissionList());            return info;        }        // 返回null的话,就会导致任何用户访问被拦截的请求时,都会自动跳转到unauthorizedUrl指定的地址        return null;    }}

用户实体类User:

package com.example.demo.entities;import org.hibernate.annotations.GenericGenerator;import org.springframework.data.annotation.CreatedDate;import org.springframework.data.annotation.LastModifiedDate;import javax.persistence.*;import java.util.Date;import java.util.List;import java.util.Random;import java.util.UUID;import static javax.persistence.GenerationType.TABLE;import static javax.persistence.TemporalType.TIMESTAMP;@Entity@Table(name = "tab_user")public class User extends CommEntity{    @Id    @Column(name = "user_id")    @GeneratedValue(strategy = TABLE, generator = "sequence_generator")    @GenericGenerator(            name = "sequence_generator",            strategy = "org.hibernate.id.enhanced.TableGenerator",            parameters = {                    @org.hibernate.annotations.Parameter(name = "segment_value", value = "user"),                    @org.hibernate.annotations.Parameter(name = "increment_size", value = "100"),                    @org.hibernate.annotations.Parameter(name = "optimizer", value = "pooled")            })    private Long id;    @Column(name = "user_name",nullable = false,unique = true)    private String name;    @Column(name = "password",nullable = false)    private String password;    @Column(name = "user_salt",nullable = false)    private String salt = UUID.randomUUID().toString();    @Column(name = "user_status")    private Integer status = 1;    @Column(name = "is_locked")    private IsLocked isLocked = IsLocked.LOCKED;    @Transient    private List<String> roleList;    @Transient    private List<String> permissionList;    public Long getId() {        return id;    }    public void setId(Long id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password;    }    public Integer getStatus() {        return status;    }    public void setStatus(Integer status) {        this.status = status;    }    public List<String> getRoleList() {        return roleList;    }    public void setRoleList(List<String> roleList) {        this.roleList = roleList;    }    public List<String> getPermissionList() {        return permissionList;    }    public void setPermissionList(List<String> permissionList) {        this.permissionList = permissionList;    }    public String getSalt() {        return salt;    }    public void setSalt(String salt) {        this.salt = salt;    }    public IsLocked getIsLocked() {        return isLocked;    }    public void setIsLocked(IsLocked isLocked) {        this.isLocked = isLocked;    }    public static enum IsLocked{        LOCKED("锁定"),UNLOCKED("正常");        IsLocked(String type){            this.type = type;        }        private String type;        public String getType() {            return type;        }        public void setType(String type) {            this.type = type;        }        public static IsLocked getValue(Integer i){            switch (i){                case 0:                    return LOCKED;                case 1:                    return UNLOCKED;                default:                    return null;            }        }    }}

角色实体类Role:

package com.example.demo.entities;import org.hibernate.annotations.GenericGenerator;import org.springframework.data.annotation.CreatedDate;import org.springframework.data.annotation.LastModifiedDate;import javax.persistence.*;import java.util.Date;import java.util.List;import static javax.persistence.GenerationType.TABLE;import static javax.persistence.TemporalType.TIMESTAMP;/** * Created by John.Zhang on 2017/10/11. */@Entity@Table(name = "tab_sys_role")public class Role extends CommEntity{    @Id    @Column(name = "role_id")    @GeneratedValue(strategy = TABLE, generator = "sequence_generator")    @GenericGenerator(            name = "sequence_generator",            strategy = "org.hibernate.id.enhanced.TableGenerator",            parameters = {                    @org.hibernate.annotations.Parameter(name = "segment_value", value = "role"),                    @org.hibernate.annotations.Parameter(name = "increment_size", value = "1"),                    @org.hibernate.annotations.Parameter(name = "optimizer", value = "pooled")            })    private Long id;    @Column(name = "role_name",unique = true,nullable = false)    private String name;    @Column(name = "role_type",nullable = false)    private Short type;    @Transient    private List<Permission> permissionList;    public Long getId() {        return id;    }    public void setId(Long id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public Short getType() {        return type;    }    public void setType(Short type) {        this.type = type;    }    public List<Permission> getPermissionList() {        return permissionList;    }    public void setPermissionList(List<Permission> permissionList) {        this.permissionList = permissionList;    }}

用户角色映射类UserRole:

package com.example.demo.entities;import org.hibernate.annotations.GenericGenerator;import javax.persistence.*;import static javax.persistence.GenerationType.TABLE;/** * Created by John.Zhang on 2017/10/11. */@Entity@Table(name = "tab_user_role")public class UserRole extends CommEntity{    @Id    @Column(name = "user_role_id")    @GeneratedValue(strategy = TABLE, generator = "sequence_generator")    @GenericGenerator(            name = "sequence_generator",            strategy = "org.hibernate.id.enhanced.TableGenerator",            parameters = {                    @org.hibernate.annotations.Parameter(name = "segment_value", value = "user_role"),                    @org.hibernate.annotations.Parameter(name = "increment_size", value = "1"),                    @org.hibernate.annotations.Parameter(name = "optimizer", value = "pooled")            })    private Long id;    @ManyToOne(fetch = FetchType.LAZY)    @JoinColumn(name = "user_id")    private User user;    @ManyToOne(fetch = FetchType.LAZY)    @JoinColumn(name = "role_id")    private Role role;    @Column(name = "note")    private String note;    public Long getId() {        return id;    }    public void setId(Long id) {        this.id = id;    }    public User getUser() {        return user;    }    public void setUser(User user) {        this.user = user;    }    public Role getRole() {        return role;    }    public void setRole(Role role) {        this.role = role;    }    public String getNote() {        return note;    }    public void setNote(String note) {        this.note = note;    }}

权限基础类Permission:

package com.example.demo.entities;import org.hibernate.annotations.GenericGenerator;import org.springframework.data.annotation.CreatedDate;import org.springframework.data.annotation.LastModifiedDate;import javax.persistence.*;import java.util.Date;import static javax.persistence.GenerationType.TABLE;import static javax.persistence.TemporalType.TIMESTAMP;/** * Created by John.Zhang on 2017/10/11. */@Entity@Table(name = "tab_sys_permission")public class Permission extends CommEntity{    @Id    @Column(name = "permission_id")    @GeneratedValue(strategy = TABLE, generator = "sequence_generator")    @GenericGenerator(            name = "sequence_generator",            strategy = "org.hibernate.id.enhanced.TableGenerator",            parameters = {                    @org.hibernate.annotations.Parameter(name = "segment_value", value = "permission"),                    @org.hibernate.annotations.Parameter(name = "increment_size", value = "1"),                    @org.hibernate.annotations.Parameter(name = "optimizer", value = "pooled")            })    private Long id;    @Column(name = "permission_name",unique = true,nullable = false)    private String name;    @Column(name = "permission_url")    private String url;    public Long getId() {        return id;    }    public void setId(Long id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getUrl() {        return url;    }    public void setUrl(String url) {        this.url = url;    }}

角色权限映射类RolePermission:

package com.example.demo.entities;import org.hibernate.annotations.GenericGenerator;import javax.persistence.*;import static javax.persistence.GenerationType.TABLE;/** * Created by John.Zhang on 2017/10/11. */@Entity@Table(name = "tab_role_permission")public class RolePermission extends CommEntity{    @Id    @Column(name = "role_permission_id")    @GeneratedValue(strategy = TABLE, generator = "sequence_generator")    @GenericGenerator(            name = "sequence_generator",            strategy = "org.hibernate.id.enhanced.TableGenerator",            parameters = {                    @org.hibernate.annotations.Parameter(name = "segment_value", value = "role_permission"),                    @org.hibernate.annotations.Parameter(name = "increment_size", value = "1"),                    @org.hibernate.annotations.Parameter(name = "optimizer", value = "pooled")            })    private Long id;    @ManyToOne(fetch = FetchType.LAZY)    @JoinColumn(name = "role_id")    private Role role;    @ManyToOne(fetch = FetchType.LAZY)    @JoinColumn(name = "permission_id")    private Permission permission;    @Column(name = "note")    private String note;    public Long getId() {        return id;    }    public void setId(Long id) {        this.id = id;    }    public Role getRole() {        return role;    }    public void setRole(Role role) {        this.role = role;    }    public Permission getPermission() {        return permission;    }    public void setPermission(Permission permission) {        this.permission = permission;    }    public String getNote() {        return note;    }    public void setNote(String note) {        this.note = note;    }}

公用实体类CommEntity:

package com.example.demo.entities;import org.springframework.data.annotation.CreatedDate;import org.springframework.data.annotation.LastModifiedDate;import javax.persistence.Column;import javax.persistence.Temporal;import java.util.Date;import static javax.persistence.TemporalType.TIMESTAMP;/** * Created by John.Zhang on 2017/10/11. */public class CommEntity {    @CreatedDate    @Temporal(TIMESTAMP)    @Column(name = "create_time")    private Date createTime = new Date();    @LastModifiedDate    @Temporal(TIMESTAMP)    @Column(name = "modified_date")    private Date modifiedDate;    public Date getCreateTime() {        return createTime;    }    public void setCreateTime(Date createTime) {        this.createTime = createTime;    }    public Date getModifiedDate() {        return modifiedDate;    }    public void setModifiedDate(Date modifiedDate) {        this.modifiedDate = modifiedDate;    }}

登录Controller :

package com.example.demo.controller;import com.example.demo.entities.User;import com.example.demo.entities.UserToken;import com.example.demo.service.UserSevice;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;/** * Created by John.Zhang on 2017/10/9. */@RestControllerpublic class LoginController {    @Autowired    private UserSevice userSevice;    @PostMapping(value = "login")    public HashMap<String,Object> login(@RequestBody UserToken userToken){        return userSevice.login(userToken);    }    @PostMapping(value = "getLoginUser")    public User getLoginUser(){        return userSevice.getLoginUser();    }}

路径跳转Controller :

package com.example.demo.controller;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;/** * Created by John.Zhang on 2017/10/9. */@Controllerpublic class PathController {    private String LoginPath = "Login";    private String IndexPath = "index";    @RequestMapping(value = "/")    public String loginInit(){        return LoginPath;    }    @RequestMapping(value = "index")    public String toIndex(){        return IndexPath;    }}

方法实现类(接口类不贴了,自动生成就行):

package com.example.demo.service.impl;import com.example.demo.entities.*;import com.example.demo.repository.*;import com.example.demo.service.UserSevice;import com.example.demo.utils.DataTransUtil;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.IncorrectCredentialsException;import org.apache.shiro.authc.LockedAccountException;import org.apache.shiro.authc.UnknownAccountException;import org.apache.shiro.authc.UsernamePasswordToken;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.util.ArrayList;import java.util.HashMap;import java.util.List;/** * Created by John.Zhang on 2017/10/9. */@Servicepublic class UserSeviceImpl implements UserSevice{    @Autowired    private UserRepository userRepository;    @Autowired    private UserRoleRepository userRoleRepository;    @Autowired    private RolePermissionRepository rolePermissionRepository;    @Autowired    private RoleRepository roleRepository;    @Autowired    private PermissionRepository permissionRepository;    @Override    public HashMap<String, Object> login(UserToken userToken) {        UsernamePasswordToken token = new UsernamePasswordToken(userToken.getUsername(), userToken.getPassword());        try {            SecurityUtils.getSubject().login(token);        }catch (UnknownAccountException e){            return DataTransUtil.returnData(0,"用户名不存在");        }catch (IncorrectCredentialsException e) {            return DataTransUtil.returnData(0, "密码错误");        }catch (LockedAccountException e){            return DataTransUtil.returnData(0,"用户已被锁定,无法登录");        }catch (Exception e){            return DataTransUtil.returnData(0,"其他错误");        }        return DataTransUtil.returnData();    }    @Override    public User findByName(String username) {        return userRepository.findByName(username);    }    @Override    public User getLoginUser() {        return (User)SecurityUtils.getSubject().getPrincipal();    }    @Override    public List<Role> findRolesByUid(Long id) {        List<UserRole> userRoleList = userRoleRepository.findRolesByUid(id);        List<Role> roleList = new ArrayList<>();        for(UserRole userRole : userRoleList){            roleList.add(userRole.getRole());        }        return roleList;    }    @Override    public List<Permission> findPermissionsByUid(Long id) {        List<UserRole> userRoleList = userRoleRepository.findRolesByUid(id);        List<Long> roleIds = new ArrayList<>();        for(UserRole userRole : userRoleList){            roleIds.add(userRole.getRole().getId());        }        List<RolePermission> rolePermissionList = rolePermissionRepository.findPermissionsByUid(roleIds);        List<Permission> permissionList = new ArrayList<>();        for(RolePermission rolePermission : rolePermissionList){            if(!permissionList.contains(rolePermission.getPermission())){                permissionList.add(rolePermission.getPermission());            }        }        return permissionList;    }}

Dao层(详细代码不贴了,自己定义就行):
这里写图片描述

工具类:

package com.example.demo.utils;import org.springframework.util.StringUtils;import java.util.HashMap;/** * Created by lean on 2017/9/18. */public class DataTransUtil {    private static Integer defaultCode = 1;    private static String defaultMessage = "succesful";    public static HashMap<String,Object> returnData(Integer code,String message,Object data){        HashMap<String,Object> map = new HashMap<>();        if(null != code){            map.put("code",code);        }else{            map.put("code",defaultCode);        }        if(!StringUtils.isEmpty(message)){            map.put("message",message);        }else{            map.put("message",defaultMessage);        }        map.put("data",data);        return map;    }    public static HashMap<String,Object> returnData(Object data){        return returnData(null,null,data);    }    public static HashMap<String,Object> returnData(){        return returnData(null,null,null);    }    public static HashMap<String,Object> returnData(Integer code,String message){        return returnData(code,message,null);    }}

从 getLoginUser 接口方法获得登录用户信息展示:
这里写图片描述

附加-密码加密方法:

package com.example.demo;import org.apache.shiro.crypto.hash.Md5Hash;import org.apache.shiro.crypto.hash.SimpleHash;import org.apache.shiro.util.ByteSource;/** * Created by John.Zhang on 2017/10/11. */public class Test {    public static void main(String[] args) {        String newPassword = new SimpleHash(                "MD5",           //加密算法                "123",      //密码                ByteSource.Util.bytes("10086"),  //salt盐   username + salt                2   //迭代次数        ).toHex();        System.out.print(newPassword);    }}
原创粉丝点击