SpringBoot整合Shiro

SpringBoot中引用Shiro进行基本的登陆验证,orm框架使用Spring Data JPA 默认实现是Hibernate。

pom中引入Shiro依赖

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring-boot-starter -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.8.0</version>
        </dependency>

appliaction.yml

server:
  port: 8090

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/remind?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true&createDatabaseIfNotExist=true
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123
  jpa:
    hibernate:
      ddl-auto: update
    database-platform: org.hibernate.dialect.MySQL55Dialect
    show-sql: false

编写存储用户的实体类

  1. BaseEntity.java 将一些entitiy中通用的字段放到BaseEntity中
@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
@MappedSuperclass
public abstract class BaseEntity implements Serializable {
    @Id
    @GeneratedValue(generator = "uuidGen")
    @GenericGenerator(name = "uuidGen", strategy = "uuid")
    private String uuid;

    private Date createTime;

    private Date updateTime;
}
  1. UserEntity.java
@Table(name = "t_user")
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@SuperBuilder
@EqualsAndHashCode(callSuper = true)
public class UserEntity extends BaseEntity {

    @Column(unique = true,nullable = false) //设置唯一约束
    private String name;

    @Column(nullable = false)  //设置不能为null
    private String password;

    private String email;

    @Column(columnDefinition = "varchar(255) default '北京' ") //设置默认值
    private String city;

}

dao层

@Repository
public interface UserRepository extends JpaRepository<UserEntity, String> {
    UserEntity findUserEntityByName(String name); //指定命名方法名,可以直接解析查询name字段
}

service层

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    UserRepository userRepo;

    @Override
    public UserEntity saveUser(UserEntity user) {
        return null;
    }

    @Override
    public UserEntity findUserByName(String name) {
        UserEntity user = userRepo.findUserEntityByName(name);
        if(null == user) throw new RuntimeException("用户不存在");
        return user;
    }

    @Override
    public UserEntity login(String name, String password) {
        UsernamePasswordToken token = new UsernamePasswordToken(name, password);
        Subject subject = SecurityUtils.getSubject();
        subject.login(token);
        return null;
    }
}

自定义AuthorizingRealm

@Component
public class MyRealm extends AuthorizingRealm {
    @Autowired
    UserService userService;
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
    //验证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //1获取用户身份信息
        String name = authenticationToken.getPrincipal().toString();
        //2数据库中查找用户
        UserEntity user = userService.findUserByName(name);
        if(null != user) {
            HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
            matcher.setHashAlgorithmName("MD5"); //设置为MD5加密算法
            matcher.setHashIterations(3); //设置hash迭代次数,多次迭代安全性提高
            return new SimpleAuthenticationInfo(
                    authenticationToken.getPrincipal(),
                    user.getPassword(),
                    ByteSource.Util.bytes("sallai"),
                    name
            );
        }
        return null;
    }
}

Shiro配置类

@Configuration
public class ShiroConfig {

    @Autowired
    MyRealm realm;

    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashIterations(3);
        matcher.setHashAlgorithmName("MD5");
        realm.setCredentialsMatcher(matcher);
        securityManager.setRealm(realm);
        return securityManager;
    }

    @Bean(name = "shiroFilterFactoryBean")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(securityManager);
        bean.setLoginUrl("/api/user/loginPage"); //设置登陆页路径
        bean.setSuccessUrl("/index"); 
        Map<String, String> map = new LinkedHashMap<>();
        map.put("/api/user/login", "anon"); //放行路径
        map.put("/**", "authc"); //拦截所有放在最后
        bean.setFilterChainDefinitionMap(map);
        return bean;
    }
}

返回R类

@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
public  class R {
    private int code;
    private String msg;
    private Object data;

    private final static Integer SUCCESS_CODE = 200;
    private final static Integer FAIL_CODE = 401;
    private final static String SUCCESS_TIP_DEFAULT = "操作成功";
    private final static String FAIL_TIP_DEFAULT = "操作失败!";

    public static R success(){
        R r = new R();
        r.setCode(SUCCESS_CODE);
        r.setMsg(SUCCESS_TIP_DEFAULT);
        return r;
    }

    public static R fail(){
        R r = new R();
        r.setCode(FAIL_CODE);
        r.setMsg(FAIL_TIP_DEFAULT);
        return r;
    }

    public R setMsg(String msg) {
        this.msg = msg;
        return this;
    }
    @Override
    public String toString() {
        return JSON.toJSONString(this);
    }
}

编写Controller测试

@RestController
@RequestMapping("/api/user")
public class UserController {
    @Autowired
    UserService userService;

    @GetMapping("login")
    public R userLogin(String name,String password) {
        userService.login(name, password);
        return R.success().setMsg("登陆成功!");
    }

    @GetMapping("loginPage")
    public R userLoginPage() {

        return R.success().setMsg("please login");
    }
}

全局异常处理

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler(value = {RuntimeException.class})
    public R handleRuntimeException(RuntimeException runtimeException) {
        log.info("捕获全局异常->"+runtimeException.getLocalizedMessage().toString());
        return R.fail().setMsg(runtimeException.getLocalizedMessage().toString());
    }
}

编写测试,生成对应加盐,三次MD5密码

	@Test
    public void genMd5Password(){
        Md5Hash hash = new Md5Hash("123", "sallai", 3); //明文密码 123,slat盐值 sallai,hash迭代次数,与代码中写的次数要一直,不然检验的时候对应不上。
        log.info(hash.toHex());
        //将打印的结果,添加的数据中的password字段中,name自己写一个。我这里sallai用户名
    }

测试

正确测试
在这里插入图片描述
异常测试
在这里插入图片描述
这里可以在subject.login()中,trycatch一下,捕获对应的用户名不存在异常和密码验证失败异常,手动抛出运行时异常信息,填写对应的异常提示消息,然后这里就会得到对应的异常提示信息。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值