我的java历程中之shiro框架与spring整合

时光怂恿深爱的人放手 提交于 2020-03-12 11:02:46

任何框架要用首先要到pom依赖 。。。
在这里插入图片描述
在shiro.xml配置文件配置shiro相关信息
在这里插入图片描述
因为securityManager需要realm
在这里插入图片描述

package com.ssq.realm;


import com.ssq.pojo.User;
import com.ssq.service.RoleService;
import com.ssq.service.UserService;
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.springframework.beans.factory.annotation.Autowired;

import java.util.Set;

public class UserRealm extends AuthorizingRealm {
    @Autowired
    private UserService us;
    @Autowired
    private RoleService rs;


    /**
     * 授权
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
       User user= (User) principals.getPrimaryPrincipal();
        //根据用户名去获取账户的角色和权限
       Set<String> roles= rs.findRoles(user.getLoginName());
       Set<String> permissions= rs.findPermissions(user.getLoginName());
       SimpleAuthorizationInfo sai = new SimpleAuthorizationInfo();
       //把查出的权限给SimpleAuthorizationInfo 进行判断
       sai.addRoles(roles);
       sai.addStringPermissions(permissions);
       return sai;
    }


    /**
     * 认证
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username =(String) token.getPrincipal();
        User user= us.findByLoginName(username);
        //判断用户不存在
        if (user==null) {
            throw new UnknownAccountException();
        }
        return new SimpleAuthenticationInfo(
                user,//用户信息 用户对象
                user.getPassword(),//密码
                ByteSource.Util.bytes(user.getLoginName()),//salt
                getName()//realm的名称
        );
    }
}

我在java类里写了关于realm
这个类里的realm通过service去找dao dao去找mapper 根据用户名查出该用户的角色和权限

  @RequestMapping("/login")
    public String login(String loginName, String password, Model model, HttpSession session){
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token=new UsernamePasswordToken(loginName,password);
        try {
            subject.login(token);
            User user = (User) subject.getPrincipal();
            //http提供的session
            //session.setAttribute("user",user);
            //使用shiro提供的session
            System.out.println(subject.getSession()==session);
            subject.getSession().setAttribute("user",user);
            //http的session与shiro是一样的
            return "forward:/product/findAll";
        }catch (UnknownAccountException e){
          model.addAttribute("loginError","用户名不存在");
        }catch (IncorrectCredentialsException e){
          model.addAttribute("loginError","密码不正确");
        }catch (AuthenticationException e){
            model.addAttribute("loginError","登陆失败");
        }
        return "login";
    }

这是controller里的

还有配置shiro过滤规则 只有把所有请求经过shiro过滤器 shiro 才能对所有请求进行拦截 然后进行认证授权

package com.ssq.filter;

import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
 * 自定义角色验证过滤器
 */
public class CustomRolesAuthorizationFilter extends AuthorizationFilter {
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object o)
            throws Exception {
        Subject subject=getSubject(request,response);
        String[] rolesArray=(String[]) o;

        if (rolesArray==null||rolesArray.length==0){
            return  true;
        }
        //判断角色  只要要任何一个角色就可以访问
        for (int i=0;i<rolesArray.length;i++){
            if (subject.hasRole(rolesArray[i])) {
            return true;
            }
        }
        return false;
    }
}

然后在shiro配置文件里配置

<bean id="customRoles" class="com.ssq.filter.CustomRolesAuthorizationFilter"/>

以及web.xml过滤器

  <!--配置Shiro过滤器  用来拦截所有请求 进行认证和授权-->
    <!--然后在spring-shiro配置文件中 配置和这里一模一样的名字的bean shrioFilter-->
    <filter>
        <filter-name>shrioFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>transformWsdlLocations</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>shrioFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

1.首先是密码加密

package com.ssq.service.impl;

import com.ssq.vo.PasswordVo;
import org.apache.shiro.authc.credential.PasswordService;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class PasswordServiceImpl implements PasswordService {
    @Value("${algorithmName}")
    private String algorithmName;
    @Value("${hashIterations}")
    private int hashIterations;

    @Override
    public String encryptPassword(Object PasswordVo) throws IllegalArgumentException {
        PasswordVo Vo = (com.ssq.vo.PasswordVo) PasswordVo;
        return new SimpleHash(algorithmName,Vo.getPassword(),Vo.getSalt(),hashIterations).toBase64();
    }

    @Override
    public boolean passwordsMatch(Object submittedPlaintext, String encrypted) {
        return false;
    }
}

在service层调用

package com.ssq.service.impl;

import com.ssq.dao.UserDao;
import com.ssq.pojo.User;
import com.ssq.service.UserService;
import com.ssq.vo.PasswordVo;
import org.apache.shiro.authc.credential.PasswordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Map;

@Service
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao ud;
    @Autowired
    private PasswordService ps;

    @Override
    public int register(Map<String, Object> map) {
        //对明文密码进行加密
        PasswordVo vo=new PasswordVo();
        String password = (String) map.get("password");
        System.out.println("密码:"+password);
        String loginName =(String) map.get("loginName");
        System.out.println("用户名:"+loginName);
        vo.setPassword(password);
        vo.setSalt(loginName);
        //加密后的密码
        String str = ps.encryptPassword(vo);
        Map<String,Object> map1=new HashMap<>();
        map1.put("loginName",loginName);
        map1.put("password",str);
        return ud.register(map1);
    }

这是vo

package com.ssq.vo;

import java.io.Serializable;

public class PasswordVo implements Serializable {
    private String password;
    private String salt;

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getSalt() {
        return salt;
    }

    public void setSalt(String salt) {
        this.salt = salt;
    }
}

并在配置文件properties里配置算法以及散列次数
在这里插入图片描述

然后就是controller调用service

@Controller
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService us;

    //注册
    @RequestMapping("/register")
    public String register(String loginName,String password){
        Map<String,Object> map=new HashMap<>();
        map.put("loginName",loginName);
        map.put("password",password);
        us.register(map);
        return "login";
    }

然后就是密码解密 登录

 //登录
    @RequestMapping("/login")
    public String login(String loginName, String password, Model model, HttpSession session){
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token=new UsernamePasswordToken(loginName,password);
        try {
            subject.login(token);
            User user = (User) subject.getPrincipal();
            //http提供的session
            //session.setAttribute("user",user);
            //使用shiro提供的session
            System.out.println(subject.getSession()==session);
            subject.getSession().setAttribute("user",user);
            //http的session与shiro是一样的
            return "forward:/product/findAll";
        }catch (UnknownAccountException e){
          model.addAttribute("loginError","用户名不存在");
        }catch (IncorrectCredentialsException e){
          model.addAttribute("loginError","密码不正确");
        }catch (AuthenticationException e){
            model.addAttribute("loginError","登陆失败");
        }
        return "login";
    }

登录也就是解密

    /**
     * 认证
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username =(String) token.getPrincipal();
        User user= us.findByLoginName(username);
        //判断用户不存在
        if (user==null) {
            throw new UnknownAccountException();
        }
        return new SimpleAuthenticationInfo(
                user,//用户信息 用户对象
                user.getPassword(),//密码
                ByteSource.Util.bytes(user.getLoginName()),//salt
                getName()//realm的名称
        );
    }
}

realm需要密码匹配器


    <!--配置密码匹配器-->
    <!--realm需要密码匹配器-->
    <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
        <!--密码匹配器需要算法-->
        <!--这个就是encrypt.properties里面配置好的算法以及散列次数  以后只需改那里面的就行-->
        <property name="hashAlgorithmName" value="${algorithmName}"></property>
        <!--散列次数-->
        <property name="hashIterations" value="${hashIterations}"></property>
        <!--在UserServiceImpl中用的编码方式是tobase64  而默认的编码方式是16进制-->
        <!--所以我们需要将默认改为false-->
        <property name="storedCredentialsHexEncoded" value="false"></property>
    </bean>

登陆成功 根据用户名查询该用户的拥有什么权限和角色


<mapper namespace="com.ssq.dao.RoleDao">
    <select id="selectRoles" resultType="string" parameterType="string">
        select tr.role_name
        from shiro.t_user tu
         left join shiro.user_role ur
            on tu.id=ur.user_id
         left join shiro.t_role tr
            on ur.role_id=tr.id
        where tu.login_name=#{username}
    </select>

    <select id="selectPermissions" resultType="string" parameterType="string">
        select tp.permission_name
        from shiro.t_user tu
            left join shiro.user_role ur
            on tu.id=ur.user_id
            left join shiro.t_role tr
            on ur.role_id=tr.id
            left join shiro.role_permisstion rp
            on rp.role_id=tr.id
            left join shiro.t_permisstion tp
            on tp.id=rp.permission_id
        where tu.login_name=#{username}
    </select>

  <!--定义一个名为shrioFilter的 这里的bean的id要与web.xml配置的shiro过滤器名称一致-->
    <!--用来配置url过滤规则-->
    <bean id="shrioFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!--配置securityManager-->
        <property name="securityManager" ref="securityManager"></property>

        <!--配置url过滤规则-->
        <property name="filterChainDefinitions">
            <value>
                <!--anon不需要登陆认证-->
                <!--authc需要登陆认证-->
                /showLogin= anon
                 /product/**=authc
                /teacher/delete=authc,perms[teacher:delete]
                <!--这里要重写权限的验证 默认是并且的关系 我们这里重写后 登陆者只需要满足其中一个角色即可-->
                /teacher/**=authc,customRoles[teacher,manager]
                /student/**=authc,roles[student]
            </value>
        </property>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!